From 6a40dc5ab5036722d8102ba7190dbd9d72982637 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Mon, 13 Oct 2014 11:37:18 +0530 Subject: ALSA: au88x0: added reference of vortex_t added a pointer of the vortex in the following functions : vortex_alsafmt_aspfmt vortex_Vort3D_InitializeSource a3dsrc_ZeroStateA3D so that we can have a reference of the vortex in the function. this reference of the vortex will actually be used in a later patch to convert the pr_* macro to dev_*. Signed-off-by: Sudip Mukherjee Signed-off-by: Takashi Iwai --- sound/pci/au88x0/au88x0.h | 4 ++-- sound/pci/au88x0/au88x0_a3d.c | 6 +++--- sound/pci/au88x0/au88x0_core.c | 5 +++-- sound/pci/au88x0/au88x0_pcm.c | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/pci/au88x0/au88x0.h b/sound/pci/au88x0/au88x0.h index 466a5c8e8354..3a8fefefea77 100644 --- a/sound/pci/au88x0/au88x0.h +++ b/sound/pci/au88x0/au88x0.h @@ -243,7 +243,7 @@ static int vortex_core_init(vortex_t * card); static int vortex_core_shutdown(vortex_t * card); static void vortex_enable_int(vortex_t * card); static irqreturn_t vortex_interrupt(int irq, void *dev_id); -static int vortex_alsafmt_aspfmt(int alsafmt); +static int vortex_alsafmt_aspfmt(int alsafmt, vortex_t *v); /* Connection stuff. */ static void vortex_connect_default(vortex_t * vortex, int en); @@ -278,7 +278,7 @@ static void vortex_mix_setvolumebyte(vortex_t * vortex, unsigned char mix, static void vortex_Vort3D_enable(vortex_t * v); static void vortex_Vort3D_disable(vortex_t * v); static void vortex_Vort3D_connect(vortex_t * vortex, int en); -static void vortex_Vort3D_InitializeSource(a3dsrc_t * a, int en); +static void vortex_Vort3D_InitializeSource(a3dsrc_t *a, int en, vortex_t *v); #endif /* Driver stuff. */ diff --git a/sound/pci/au88x0/au88x0_a3d.c b/sound/pci/au88x0/au88x0_a3d.c index 30f760e3d2c0..bc9cda3aa725 100644 --- a/sound/pci/au88x0/au88x0_a3d.c +++ b/sound/pci/au88x0/au88x0_a3d.c @@ -484,7 +484,7 @@ static void a3dsrc_ZeroState(a3dsrc_t * a) } /* Reset entire A3D engine */ -static void a3dsrc_ZeroStateA3D(a3dsrc_t * a) +static void a3dsrc_ZeroStateA3D(a3dsrc_t *a, vortex_t *v) { int i, var, var2; @@ -601,7 +601,7 @@ static void vortex_Vort3D_enable(vortex_t *v) Vort3DRend_Initialize(v, XT_HEADPHONE); for (i = 0; i < NR_A3D; i++) { vortex_A3dSourceHw_Initialize(v, i % 4, i >> 2); - a3dsrc_ZeroStateA3D(&(v->a3d[0])); + a3dsrc_ZeroStateA3D(&v->a3d[0], v); } /* Register ALSA controls */ vortex_a3d_register_controls(v); @@ -676,7 +676,7 @@ static void vortex_Vort3D_connect(vortex_t * v, int en) } /* Initialize one single A3D source. */ -static void vortex_Vort3D_InitializeSource(a3dsrc_t * a, int en) +static void vortex_Vort3D_InitializeSource(a3dsrc_t *a, int en, vortex_t *v) { if (a->vortex == NULL) { pr_warn diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c index 72e81286b70e..00e209617c52 100644 --- a/sound/pci/au88x0/au88x0_core.c +++ b/sound/pci/au88x0/au88x0_core.c @@ -2177,7 +2177,8 @@ vortex_adb_allocroute(vortex_t *vortex, int dma, int nr_ch, int dir, return -EBUSY; } /* (De)Initialize A3D hardware source. */ - vortex_Vort3D_InitializeSource(&(vortex->a3d[a3d]), en); + vortex_Vort3D_InitializeSource(&vortex->a3d[a3d], en, + vortex); } /* Make SPDIF out exclusive to "spdif" device when in use. */ if ((stream->type == VORTEX_PCM_SPDIF) && (en)) { @@ -2765,7 +2766,7 @@ static int vortex_core_shutdown(vortex_t * vortex) /* Alsa support. */ -static int vortex_alsafmt_aspfmt(int alsafmt) +static int vortex_alsafmt_aspfmt(int alsafmt, vortex_t *v) { int fmt; diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c index 5adc6b92ffab..bdde182f1372 100644 --- a/sound/pci/au88x0/au88x0_pcm.c +++ b/sound/pci/au88x0/au88x0_pcm.c @@ -332,7 +332,7 @@ static int snd_vortex_pcm_prepare(struct snd_pcm_substream *substream) dir = 1; else dir = 0; - fmt = vortex_alsafmt_aspfmt(runtime->format); + fmt = vortex_alsafmt_aspfmt(runtime->format, chip); spin_lock_irq(&chip->lock); if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { vortex_adbdma_setmode(chip, dma, 1, dir, fmt, -- cgit v1.2.3 From 70c84418bf74f582e29906f1eeb19f2e9da53ddd Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Mon, 13 Oct 2014 11:37:19 +0530 Subject: ALSA: au88x0: pr_* replaced with dev_* pr_* macros replaced with dev_* as they are more preffered over pr_*. each file which had pr_* was reviewed manually and replaced with dev_*. here we have actually used the reference of the vortex which was added to some functions in the previous patch of this series. The prefix of the CARD_NAME and prefix of "vortex:" was also removed as the dev_* will print the device name. Signed-off-by: Sudip Mukherjee Signed-off-by: Takashi Iwai --- sound/pci/au88x0/au88x0.c | 33 +++++++------- sound/pci/au88x0/au88x0_a3d.c | 15 ++++--- sound/pci/au88x0/au88x0_core.c | 97 +++++++++++++++++++++------------------- sound/pci/au88x0/au88x0_eq.c | 3 +- sound/pci/au88x0/au88x0_game.c | 3 +- sound/pci/au88x0/au88x0_mpu401.c | 2 +- sound/pci/au88x0/au88x0_pcm.c | 6 +-- sound/pci/au88x0/au88x0_synth.c | 17 ++++--- 8 files changed, 94 insertions(+), 82 deletions(-) (limited to 'sound') diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c index 21ce31f636bc..e9c3833f6d44 100644 --- a/sound/pci/au88x0/au88x0.c +++ b/sound/pci/au88x0/au88x0.c @@ -48,11 +48,10 @@ static void vortex_fix_latency(struct pci_dev *vortex) { int rc; if (!(rc = pci_write_config_byte(vortex, 0x40, 0xff))) { - pr_info( CARD_NAME - ": vortex latency is 0xff\n"); + dev_info(&vortex->dev, "vortex latency is 0xff\n"); } else { - pr_warn( CARD_NAME - ": could not set vortex latency: pci error 0x%x\n", rc); + dev_warn(&vortex->dev, + "could not set vortex latency: pci error 0x%x\n", rc); } } @@ -70,11 +69,10 @@ static void vortex_fix_agp_bridge(struct pci_dev *via) if (!(rc = pci_read_config_byte(via, 0x42, &value)) && ((value & 0x10) || !(rc = pci_write_config_byte(via, 0x42, value | 0x10)))) { - pr_info( CARD_NAME - ": bridge config is 0x%x\n", value | 0x10); + dev_info(&via->dev, "bridge config is 0x%x\n", value | 0x10); } else { - pr_warn( CARD_NAME - ": could not set vortex latency: pci error 0x%x\n", rc); + dev_warn(&via->dev, + "could not set vortex latency: pci error 0x%x\n", rc); } } @@ -97,7 +95,8 @@ static void snd_vortex_workaround(struct pci_dev *vortex, int fix) PCI_DEVICE_ID_AMD_FE_GATE_7007, NULL); } if (via) { - pr_info( CARD_NAME ": Activating latency workaround...\n"); + dev_info(&vortex->dev, + "Activating latency workaround...\n"); vortex_fix_latency(vortex); vortex_fix_agp_bridge(via); } @@ -153,7 +152,7 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip) return err; if (pci_set_dma_mask(pci, DMA_BIT_MASK(32)) < 0 || pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32)) < 0) { - pr_err( "error to set DMA mask\n"); + dev_err(card->dev, "error to set DMA mask\n"); pci_disable_device(pci); return -ENXIO; } @@ -182,7 +181,7 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip) chip->mmio = pci_ioremap_bar(pci, 0); if (!chip->mmio) { - pr_err( "MMIO area remap failed.\n"); + dev_err(card->dev, "MMIO area remap failed.\n"); err = -ENOMEM; goto ioremap_out; } @@ -191,14 +190,14 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip) * This must be done before we do request_irq otherwise we can get spurious * interrupts that we do not handle properly and make a mess of things */ if ((err = vortex_core_init(chip)) != 0) { - pr_err( "hw core init failed\n"); + dev_err(card->dev, "hw core init failed\n"); goto core_out; } if ((err = request_irq(pci->irq, vortex_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) != 0) { - pr_err( "cannot grab irq\n"); + dev_err(card->dev, "cannot grab irq\n"); goto irq_out; } chip->irq = pci->irq; @@ -342,11 +341,11 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) chip->rev = pci->revision; #ifdef CHIP_AU8830 if ((chip->rev) != 0xfe && (chip->rev) != 0xfa) { - pr_alert( - "vortex: The revision (%x) of your card has not been seen before.\n", + dev_alert(card->dev, + "The revision (%x) of your card has not been seen before.\n", chip->rev); - pr_alert( - "vortex: Please email the results of 'lspci -vv' to openvortex-dev@nongnu.org.\n"); + dev_alert(card->dev, + "Please email the results of 'lspci -vv' to openvortex-dev@nongnu.org.\n"); snd_card_free(card); err = -ENODEV; return err; diff --git a/sound/pci/au88x0/au88x0_a3d.c b/sound/pci/au88x0/au88x0_a3d.c index bc9cda3aa725..ab0f87312911 100644 --- a/sound/pci/au88x0/au88x0_a3d.c +++ b/sound/pci/au88x0/au88x0_a3d.c @@ -489,7 +489,8 @@ static void a3dsrc_ZeroStateA3D(a3dsrc_t *a, vortex_t *v) int i, var, var2; if ((a->vortex) == NULL) { - pr_err( "vortex: ZeroStateA3D: ERROR: a->vortex is NULL\n"); + dev_err(v->card->dev, + "ZeroStateA3D: ERROR: a->vortex is NULL\n"); return; } @@ -628,15 +629,15 @@ static void vortex_Vort3D_connect(vortex_t * v, int en) v->mixxtlk[0] = vortex_adb_checkinout(v, v->fixed_res, en, VORTEX_RESOURCE_MIXIN); if (v->mixxtlk[0] < 0) { - pr_warn - ("vortex: vortex_Vort3D: ERROR: not enough free mixer resources.\n"); + dev_warn(v->card->dev, + "vortex_Vort3D: ERROR: not enough free mixer resources.\n"); return; } v->mixxtlk[1] = vortex_adb_checkinout(v, v->fixed_res, en, VORTEX_RESOURCE_MIXIN); if (v->mixxtlk[1] < 0) { - pr_warn - ("vortex: vortex_Vort3D: ERROR: not enough free mixer resources.\n"); + dev_warn(v->card->dev, + "vortex_Vort3D: ERROR: not enough free mixer resources.\n"); return; } #endif @@ -679,8 +680,8 @@ static void vortex_Vort3D_connect(vortex_t * v, int en) static void vortex_Vort3D_InitializeSource(a3dsrc_t *a, int en, vortex_t *v) { if (a->vortex == NULL) { - pr_warn - ("vortex: Vort3D_InitializeSource: A3D source not initialized\n"); + dev_warn(v->card->dev, + "Vort3D_InitializeSource: A3D source not initialized\n"); return; } if (en) { diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c index 00e209617c52..4667c3232b7f 100644 --- a/sound/pci/au88x0/au88x0_core.c +++ b/sound/pci/au88x0/au88x0_core.c @@ -285,8 +285,8 @@ vortex_mixer_addWTD(vortex_t * vortex, unsigned char mix, unsigned char ch) temp = hwread(vortex->mmio, prev); //printk(KERN_INFO "vortex: mixAddWTD: while addr=%x, val=%x\n", prev, temp); if ((++lifeboat) > 0xf) { - pr_err( - "vortex_mixer_addWTD: lifeboat overflow\n"); + dev_err(vortex->card->dev, + "vortex_mixer_addWTD: lifeboat overflow\n"); return 0; } } @@ -303,7 +303,7 @@ vortex_mixer_delWTD(vortex_t * vortex, unsigned char mix, unsigned char ch) eax = hwread(vortex->mmio, VORTEX_MIXER_SR); if (((1 << ch) & eax) == 0) { - pr_err( "mix ALARM %x\n", eax); + dev_err(vortex->card->dev, "mix ALARM %x\n", eax); return 0; } ebp = VORTEX_MIXER_CHNBASE + (ch << 2); @@ -324,8 +324,8 @@ vortex_mixer_delWTD(vortex_t * vortex, unsigned char mix, unsigned char ch) //printk(KERN_INFO "vortex: mixdelWTD: 1 addr=%x, val=%x, src=%x\n", ebx, edx, src); while ((edx & 0xf) != mix) { if ((esi) > 0xf) { - pr_err( - "vortex: mixdelWTD: error lifeboat overflow\n"); + dev_err(vortex->card->dev, + "mixdelWTD: error lifeboat overflow\n"); return 0; } esp14 = ebx; @@ -492,7 +492,7 @@ vortex_src_persist_convratio(vortex_t * vortex, unsigned char src, int ratio) hwwrite(vortex->mmio, VORTEX_SRC_CONVRATIO + (src << 2), ratio); temp = hwread(vortex->mmio, VORTEX_SRC_CONVRATIO + (src << 2)); if ((++lifeboat) > 0x9) { - pr_err( "Vortex: Src cvr fail\n"); + dev_err(vortex->card->dev, "Src cvr fail\n"); break; } } @@ -684,8 +684,8 @@ vortex_src_addWTD(vortex_t * vortex, unsigned char src, unsigned char ch) temp = hwread(vortex->mmio, prev); //printk(KERN_INFO "vortex: srcAddWTD: while addr=%x, val=%x\n", prev, temp); if ((++lifeboat) > 0xf) { - pr_err( - "vortex_src_addWTD: lifeboat overflow\n"); + dev_err(vortex->card->dev, + "vortex_src_addWTD: lifeboat overflow\n"); return 0; } } @@ -703,7 +703,7 @@ vortex_src_delWTD(vortex_t * vortex, unsigned char src, unsigned char ch) eax = hwread(vortex->mmio, VORTEX_SRCBLOCK_SR); if (((1 << ch) & eax) == 0) { - pr_err( "src alarm\n"); + dev_err(vortex->card->dev, "src alarm\n"); return 0; } ebp = VORTEX_SRC_CHNBASE + (ch << 2); @@ -724,8 +724,8 @@ vortex_src_delWTD(vortex_t * vortex, unsigned char src, unsigned char ch) //printk(KERN_INFO "vortex: srcdelWTD: 1 addr=%x, val=%x, src=%x\n", ebx, edx, src); while ((edx & 0xf) != src) { if ((esi) > 0xf) { - pr_warn - ("vortex: srcdelWTD: error, lifeboat overflow\n"); + dev_warn(vortex->card->dev, + "srcdelWTD: error, lifeboat overflow\n"); return 0; } esp14 = ebx; @@ -819,8 +819,8 @@ vortex_fifo_setadbctrl(vortex_t * vortex, int fifo, int stereo, int priority, do { temp = hwread(vortex->mmio, VORTEX_FIFO_ADBCTRL + (fifo << 2)); if (lifeboat++ > 0xbb8) { - pr_err( - "Vortex: vortex_fifo_setadbctrl fail\n"); + dev_err(vortex->card->dev, + "vortex_fifo_setadbctrl fail\n"); break; } } @@ -915,7 +915,8 @@ vortex_fifo_setwtctrl(vortex_t * vortex, int fifo, int ctrl, int priority, do { temp = hwread(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2)); if (lifeboat++ > 0xbb8) { - pr_err( "Vortex: vortex_fifo_setwtctrl fail\n"); + dev_err(vortex->card->dev, + "vortex_fifo_setwtctrl fail\n"); break; } } @@ -1042,7 +1043,7 @@ static void vortex_fifo_init(vortex_t * vortex) for (x = NR_ADB - 1; x >= 0; x--) { hwwrite(vortex->mmio, addr, (FIFO_U0 | FIFO_U1)); if (hwread(vortex->mmio, addr) != (FIFO_U0 | FIFO_U1)) - pr_err( "bad adb fifo reset!"); + dev_err(vortex->card->dev, "bad adb fifo reset!"); vortex_fifo_clearadbdata(vortex, x, FIFO_SIZE); addr -= 4; } @@ -1053,9 +1054,9 @@ static void vortex_fifo_init(vortex_t * vortex) for (x = NR_WT - 1; x >= 0; x--) { hwwrite(vortex->mmio, addr, FIFO_U0); if (hwread(vortex->mmio, addr) != FIFO_U0) - pr_err( - "bad wt fifo reset (0x%08x, 0x%08x)!\n", - addr, hwread(vortex->mmio, addr)); + dev_err(vortex->card->dev, + "bad wt fifo reset (0x%08x, 0x%08x)!\n", + addr, hwread(vortex->mmio, addr)); vortex_fifo_clearwtdata(vortex, x, FIFO_SIZE); addr -= 4; } @@ -1213,8 +1214,9 @@ static int vortex_adbdma_bufshift(vortex_t * vortex, int adbdma) if (dma->period_virt >= dma->nr_periods) dma->period_virt -= dma->nr_periods; if (delta != 1) - pr_info( "vortex: %d virt=%d, real=%d, delta=%d\n", - adbdma, dma->period_virt, dma->period_real, delta); + dev_info(vortex->card->dev, + "%d virt=%d, real=%d, delta=%d\n", + adbdma, dma->period_virt, dma->period_real, delta); return delta; } @@ -1482,8 +1484,8 @@ static int vortex_wtdma_bufshift(vortex_t * vortex, int wtdma) dma->period_real = page; if (delta != 1) - pr_warn( "vortex: wt virt = %d, delta = %d\n", - dma->period_virt, delta); + dev_warn(vortex->card->dev, "wt virt = %d, delta = %d\n", + dma->period_virt, delta); return delta; } @@ -1667,9 +1669,9 @@ vortex_adb_addroutes(vortex_t * vortex, unsigned char channel, hwread(vortex->mmio, VORTEX_ADB_RTBASE + (temp << 2)) & ADB_MASK; if ((lifeboat++) > ADB_MASK) { - pr_err( - "vortex_adb_addroutes: unending route! 0x%x\n", - *route); + dev_err(vortex->card->dev, + "vortex_adb_addroutes: unending route! 0x%x\n", + *route); return; } } @@ -1703,9 +1705,9 @@ vortex_adb_delroutes(vortex_t * vortex, unsigned char channel, hwread(vortex->mmio, VORTEX_ADB_RTBASE + (prev << 2)) & ADB_MASK; if (((lifeboat++) > ADB_MASK) || (temp == ADB_MASK)) { - pr_err( - "vortex_adb_delroutes: route not found! 0x%x\n", - route0); + dev_err(vortex->card->dev, + "vortex_adb_delroutes: route not found! 0x%x\n", + route0); return; } } @@ -2045,7 +2047,9 @@ vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out, int restype) } } } - pr_err( "vortex: FATAL: ResManager: resource type %d exhausted.\n", restype); + dev_err(vortex->card->dev, + "FATAL: ResManager: resource type %d exhausted.\n", + restype); return -ENOMEM; } @@ -2173,7 +2177,8 @@ vortex_adb_allocroute(vortex_t *vortex, int dma, int nr_ch, int dir, memset(stream->resources, 0, sizeof(unsigned char) * VORTEX_RESOURCE_LAST); - pr_err( "vortex: out of A3D sources. Sorry\n"); + dev_err(vortex->card->dev, + "out of A3D sources. Sorry\n"); return -EBUSY; } /* (De)Initialize A3D hardware source. */ @@ -2422,7 +2427,7 @@ static irqreturn_t vortex_interrupt(int irq, void *dev_id) hwread(vortex->mmio, VORTEX_IRQ_SOURCE); // Is at least one IRQ flag set? if (source == 0) { - pr_err( "vortex: missing irq source\n"); + dev_err(vortex->card->dev, "missing irq source\n"); return IRQ_NONE; } @@ -2430,19 +2435,19 @@ static irqreturn_t vortex_interrupt(int irq, void *dev_id) // Attend every interrupt source. if (unlikely(source & IRQ_ERR_MASK)) { if (source & IRQ_FATAL) { - pr_err( "vortex: IRQ fatal error\n"); + dev_err(vortex->card->dev, "IRQ fatal error\n"); } if (source & IRQ_PARITY) { - pr_err( "vortex: IRQ parity error\n"); + dev_err(vortex->card->dev, "IRQ parity error\n"); } if (source & IRQ_REG) { - pr_err( "vortex: IRQ reg error\n"); + dev_err(vortex->card->dev, "IRQ reg error\n"); } if (source & IRQ_FIFO) { - pr_err( "vortex: IRQ fifo error\n"); + dev_err(vortex->card->dev, "IRQ fifo error\n"); } if (source & IRQ_DMA) { - pr_err( "vortex: IRQ dma error\n"); + dev_err(vortex->card->dev, "IRQ dma error\n"); } handled = 1; } @@ -2490,7 +2495,7 @@ static irqreturn_t vortex_interrupt(int irq, void *dev_id) } if (!handled) { - pr_err( "vortex: unknown irq source %x\n", source); + dev_err(vortex->card->dev, "unknown irq source %x\n", source); } return IRQ_RETVAL(handled); } @@ -2547,7 +2552,7 @@ vortex_codec_write(struct snd_ac97 * codec, unsigned short addr, unsigned short while (!(hwread(card->mmio, VORTEX_CODEC_CTRL) & 0x100)) { udelay(100); if (lifeboat++ > POLL_COUNT) { - pr_err( "vortex: ac97 codec stuck busy\n"); + dev_err(card->card->dev, "ac97 codec stuck busy\n"); return; } } @@ -2573,7 +2578,7 @@ static unsigned short vortex_codec_read(struct snd_ac97 * codec, unsigned short while (!(hwread(card->mmio, VORTEX_CODEC_CTRL) & 0x100)) { udelay(100); if (lifeboat++ > POLL_COUNT) { - pr_err( "vortex: ac97 codec stuck busy\n"); + dev_err(card->card->dev, "ac97 codec stuck busy\n"); return 0xffff; } } @@ -2587,7 +2592,8 @@ static unsigned short vortex_codec_read(struct snd_ac97 * codec, unsigned short udelay(100); data = hwread(card->mmio, VORTEX_CODEC_IO); if (lifeboat++ > POLL_COUNT) { - pr_err( "vortex: ac97 address never arrived\n"); + dev_err(card->card->dev, + "ac97 address never arrived\n"); return 0xffff; } } while ((data & VORTEX_CODEC_ADDMASK) != @@ -2684,7 +2690,7 @@ static void vortex_spdif_init(vortex_t * vortex, int spdif_sr, int spdif_mode) static int vortex_core_init(vortex_t *vortex) { - pr_info( "Vortex: init.... "); + dev_info(vortex->card->dev, "init started\n"); /* Hardware Init. */ hwwrite(vortex->mmio, VORTEX_CTRL, 0xffffffff); msleep(5); @@ -2729,7 +2735,7 @@ static int vortex_core_init(vortex_t *vortex) //vortex_enable_timer_int(vortex); //vortex_disable_timer_int(vortex); - pr_info( "done.\n"); + dev_info(vortex->card->dev, "init.... done.\n"); spin_lock_init(&vortex->lock); return 0; @@ -2738,7 +2744,7 @@ static int vortex_core_init(vortex_t *vortex) static int vortex_core_shutdown(vortex_t * vortex) { - pr_info( "Vortex: shutdown..."); + dev_info(vortex->card->dev, "shutdown started\n"); #ifndef CHIP_AU8820 vortex_eq_free(vortex); vortex_Vort3D_disable(vortex); @@ -2760,7 +2766,7 @@ static int vortex_core_shutdown(vortex_t * vortex) msleep(5); hwwrite(vortex->mmio, VORTEX_IRQ_SOURCE, 0xffff); - pr_info( "done.\n"); + dev_info(vortex->card->dev, "shutdown.... done.\n"); return 0; } @@ -2794,7 +2800,8 @@ static int vortex_alsafmt_aspfmt(int alsafmt, vortex_t *v) break; default: fmt = 0x8; - pr_err( "vortex: format unsupported %d\n", alsafmt); + dev_err(v->card->dev, + "format unsupported %d\n", alsafmt); break; } return fmt; diff --git a/sound/pci/au88x0/au88x0_eq.c b/sound/pci/au88x0/au88x0_eq.c index 9404ba73eaf6..9585c5c63b96 100644 --- a/sound/pci/au88x0/au88x0_eq.c +++ b/sound/pci/au88x0/au88x0_eq.c @@ -845,7 +845,8 @@ snd_vortex_peaks_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *u vortex_Eqlzr_GetAllPeaks(vortex, peaks, &count); if (count != 20) { - pr_err( "vortex: peak count error 20 != %d \n", count); + dev_err(vortex->card->dev, + "peak count error 20 != %d\n", count); return -1; } for (i = 0; i < 20; i++) diff --git a/sound/pci/au88x0/au88x0_game.c b/sound/pci/au88x0/au88x0_game.c index 72daf6cf8169..151815b857a0 100644 --- a/sound/pci/au88x0/au88x0_game.c +++ b/sound/pci/au88x0/au88x0_game.c @@ -98,7 +98,8 @@ static int vortex_gameport_register(vortex_t *vortex) vortex->gameport = gp = gameport_allocate_port(); if (!gp) { - pr_err( "vortex: cannot allocate memory for gameport\n"); + dev_err(vortex->card->dev, + "cannot allocate memory for gameport\n"); return -ENOMEM; } diff --git a/sound/pci/au88x0/au88x0_mpu401.c b/sound/pci/au88x0/au88x0_mpu401.c index 328c1943c0c3..1025e55ca854 100644 --- a/sound/pci/au88x0/au88x0_mpu401.c +++ b/sound/pci/au88x0/au88x0_mpu401.c @@ -73,7 +73,7 @@ static int snd_vortex_midi(vortex_t *vortex) /* Check if anything is OK. */ temp = hwread(vortex->mmio, VORTEX_MIDI_DATA); if (temp != MPU401_ACK /*0xfe */ ) { - pr_err( "midi port doesn't acknowledge!\n"); + dev_err(vortex->card->dev, "midi port doesn't acknowledge!\n"); return -ENODEV; } /* Enable MPU401 interrupts. */ diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c index bdde182f1372..a6d6d8d0867a 100644 --- a/sound/pci/au88x0/au88x0_pcm.c +++ b/sound/pci/au88x0/au88x0_pcm.c @@ -227,7 +227,7 @@ snd_vortex_pcm_hw_params(struct snd_pcm_substream *substream, err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (err < 0) { - pr_err( "Vortex: pcm page alloc failed!\n"); + dev_err(chip->card->dev, "Vortex: pcm page alloc failed!\n"); return err; } /* @@ -371,7 +371,7 @@ static int snd_vortex_pcm_trigger(struct snd_pcm_substream *substream, int cmd) } #ifndef CHIP_AU8810 else { - pr_info( "vortex: wt start %d\n", dma); + dev_info(chip->card->dev, "wt start %d\n", dma); vortex_wtdma_startfifo(chip, dma); } #endif @@ -384,7 +384,7 @@ static int snd_vortex_pcm_trigger(struct snd_pcm_substream *substream, int cmd) vortex_adbdma_stopfifo(chip, dma); #ifndef CHIP_AU8810 else { - pr_info( "vortex: wt stop %d\n", dma); + dev_info(chip->card->dev, "wt stop %d\n", dma); vortex_wtdma_stopfifo(chip, dma); } #endif diff --git a/sound/pci/au88x0/au88x0_synth.c b/sound/pci/au88x0/au88x0_synth.c index f094bac24291..78e12f4796f3 100644 --- a/sound/pci/au88x0/au88x0_synth.c +++ b/sound/pci/au88x0/au88x0_synth.c @@ -90,7 +90,7 @@ static int vortex_wt_allocroute(vortex_t * vortex, int wt, int nr_ch) hwwrite(vortex->mmio, WT_PARM(wt, 2), 0); temp = hwread(vortex->mmio, WT_PARM(wt, 3)); - pr_debug( "vortex: WT PARM3: %x\n", temp); + dev_dbg(vortex->card->dev, "WT PARM3: %x\n", temp); //hwwrite(vortex->mmio, WT_PARM(wt, 3), temp); hwwrite(vortex->mmio, WT_DELAY(wt, 0), 0); @@ -98,7 +98,8 @@ static int vortex_wt_allocroute(vortex_t * vortex, int wt, int nr_ch) hwwrite(vortex->mmio, WT_DELAY(wt, 2), 0); hwwrite(vortex->mmio, WT_DELAY(wt, 3), 0); - pr_debug( "vortex: WT GMODE: %x\n", hwread(vortex->mmio, WT_GMODE(wt))); + dev_dbg(vortex->card->dev, "WT GMODE: %x\n", + hwread(vortex->mmio, WT_GMODE(wt))); hwwrite(vortex->mmio, WT_PARM(wt, 2), 0xffffffff); hwwrite(vortex->mmio, WT_PARM(wt, 3), 0xcff1c810); @@ -106,7 +107,8 @@ static int vortex_wt_allocroute(vortex_t * vortex, int wt, int nr_ch) voice->parm0 = voice->parm1 = 0xcfb23e2f; hwwrite(vortex->mmio, WT_PARM(wt, 0), voice->parm0); hwwrite(vortex->mmio, WT_PARM(wt, 1), voice->parm1); - pr_debug( "vortex: WT GMODE 2 : %x\n", hwread(vortex->mmio, WT_GMODE(wt))); + dev_dbg(vortex->card->dev, "WT GMODE 2 : %x\n", + hwread(vortex->mmio, WT_GMODE(wt))); return 0; } @@ -196,14 +198,15 @@ vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt, if ((reg == 5) || ((reg >= 7) && (reg <= 10)) || (reg == 0xc)) { if (wt >= (NR_WT / NR_WT_PB)) { - pr_warn - ("vortex: WT SetReg: bank out of range. reg=0x%x, wt=%d\n", - reg, wt); + dev_warn(vortex->card->dev, + "WT SetReg: bank out of range. reg=0x%x, wt=%d\n", + reg, wt); return 0; } } else { if (wt >= NR_WT) { - pr_err( "vortex: WT SetReg: voice out of range\n"); + dev_err(vortex->card->dev, + "WT SetReg: voice out of range\n"); return 0; } } -- cgit v1.2.3 From 54841a06c54eb55918948c12ab9b5f02cacb6ab3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 15 Oct 2014 14:00:16 +0200 Subject: ALSA: seq: Use atomic ops for autoload refcount ... just to robustify for races. Signed-off-by: Takashi Iwai --- sound/core/seq/seq_device.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c index 91a786a783e1..775ea9390110 100644 --- a/sound/core/seq/seq_device.c +++ b/sound/core/seq/seq_device.c @@ -127,15 +127,15 @@ static void snd_seq_device_info(struct snd_info_entry *entry, #ifdef CONFIG_MODULES /* avoid auto-loading during module_init() */ -static int snd_seq_in_init; +static atomic_t snd_seq_in_init = ATOMIC_INIT(0); void snd_seq_autoload_lock(void) { - snd_seq_in_init++; + atomic_inc(&snd_seq_in_init); } void snd_seq_autoload_unlock(void) { - snd_seq_in_init--; + atomic_dec(&snd_seq_in_init); } #endif @@ -147,7 +147,7 @@ void snd_seq_device_load_drivers(void) /* Calling request_module during module_init() * may cause blocking. */ - if (snd_seq_in_init) + if (atomic_read(&snd_seq_in_init)) return; mutex_lock(&ops_mutex); -- cgit v1.2.3 From 68ab61084de3220e2fb0a698c890ba91decddc85 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 15 Oct 2014 14:06:25 +0200 Subject: ALSA: seq: bind seq driver automatically Currently the sequencer module binding is performed independently from the card module itself. The reason behind it is to keep the sequencer stuff optional and allow the system running without it (e.g. for using PCM or rawmidi only). This works in most cases, but a remaining problem is that the binding isn't done automatically when a new driver module is probed. Typically this becomes visible when a hotplug driver like usb audio is used. This patch tries to address this and other potential issues. First, the seq-binder (seq_device.c) tries to load a missing driver module at creating a new device object. This is done asynchronously in a workq for avoiding the deadlock (modprobe call in module init path). This action, however, should be enabled only when the sequencer stuff was already initialized, i.e. snd-seq module was already loaded. For that, a new function, snd_seq_autoload_init() is introduced here; this clears the blocking of autoloading, and also tries to load all pending driver modules. Reported-by: Adam Goode Signed-off-by: Takashi Iwai --- include/sound/seq_kernel.h | 4 ++ sound/core/seq/seq.c | 3 ++ sound/core/seq/seq_device.c | 92 +++++++++++++++++++++++++++++++++------------ 3 files changed, 76 insertions(+), 23 deletions(-) (limited to 'sound') diff --git a/include/sound/seq_kernel.h b/include/sound/seq_kernel.h index 2398521f0998..eea5400fe373 100644 --- a/include/sound/seq_kernel.h +++ b/include/sound/seq_kernel.h @@ -108,9 +108,13 @@ int snd_seq_event_port_detach(int client, int port); #ifdef CONFIG_MODULES void snd_seq_autoload_lock(void); void snd_seq_autoload_unlock(void); +void snd_seq_autoload_init(void); +#define snd_seq_autoload_exit() snd_seq_autoload_lock() #else #define snd_seq_autoload_lock() #define snd_seq_autoload_unlock() +#define snd_seq_autoload_init() +#define snd_seq_autoload_exit() #endif #endif /* __SOUND_SEQ_KERNEL_H */ diff --git a/sound/core/seq/seq.c b/sound/core/seq/seq.c index 712110561082..bebdd2e920ca 100644 --- a/sound/core/seq/seq.c +++ b/sound/core/seq/seq.c @@ -110,6 +110,7 @@ static int __init alsa_seq_init(void) if ((err = snd_seq_system_client_init()) < 0) goto error; + snd_seq_autoload_init(); error: snd_seq_autoload_unlock(); return err; @@ -131,6 +132,8 @@ static void __exit alsa_seq_exit(void) /* release event memory */ snd_sequencer_memory_done(); + + snd_seq_autoload_exit(); } module_init(alsa_seq_init) diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c index 775ea9390110..a8e2c6016800 100644 --- a/sound/core/seq/seq_device.c +++ b/sound/core/seq/seq_device.c @@ -56,6 +56,7 @@ MODULE_LICENSE("GPL"); #define DRIVER_LOADED (1<<0) #define DRIVER_REQUESTED (1<<1) #define DRIVER_LOCKED (1<<2) +#define DRIVER_REQUESTING (1<<3) struct ops_list { char id[ID_LEN]; /* driver id */ @@ -127,7 +128,7 @@ static void snd_seq_device_info(struct snd_info_entry *entry, #ifdef CONFIG_MODULES /* avoid auto-loading during module_init() */ -static atomic_t snd_seq_in_init = ATOMIC_INIT(0); +static atomic_t snd_seq_in_init = ATOMIC_INIT(1); /* blocked as default */ void snd_seq_autoload_lock(void) { atomic_inc(&snd_seq_in_init); @@ -137,32 +138,72 @@ void snd_seq_autoload_unlock(void) { atomic_dec(&snd_seq_in_init); } -#endif -void snd_seq_device_load_drivers(void) +static void autoload_drivers(void) { -#ifdef CONFIG_MODULES - struct ops_list *ops; + /* avoid reentrance */ + if (atomic_inc_return(&snd_seq_in_init) == 1) { + struct ops_list *ops; + + mutex_lock(&ops_mutex); + list_for_each_entry(ops, &opslist, list) { + if ((ops->driver & DRIVER_REQUESTING) && + !(ops->driver & DRIVER_REQUESTED)) { + ops->used++; + mutex_unlock(&ops_mutex); + ops->driver |= DRIVER_REQUESTED; + request_module("snd-%s", ops->id); + mutex_lock(&ops_mutex); + ops->used--; + } + } + mutex_unlock(&ops_mutex); + } + atomic_dec(&snd_seq_in_init); +} - /* Calling request_module during module_init() - * may cause blocking. - */ - if (atomic_read(&snd_seq_in_init)) - return; +static void call_autoload(struct work_struct *work) +{ + autoload_drivers(); +} - mutex_lock(&ops_mutex); - list_for_each_entry(ops, &opslist, list) { - if (! (ops->driver & DRIVER_LOADED) && - ! (ops->driver & DRIVER_REQUESTED)) { - ops->used++; - mutex_unlock(&ops_mutex); - ops->driver |= DRIVER_REQUESTED; - request_module("snd-%s", ops->id); - mutex_lock(&ops_mutex); - ops->used--; - } +static DECLARE_WORK(autoload_work, call_autoload); + +static void try_autoload(struct ops_list *ops) +{ + if (!ops->driver) { + ops->driver |= DRIVER_REQUESTING; + schedule_work(&autoload_work); } +} + +static void queue_autoload_drivers(void) +{ + struct ops_list *ops; + + mutex_lock(&ops_mutex); + list_for_each_entry(ops, &opslist, list) + try_autoload(ops); mutex_unlock(&ops_mutex); +} + +void snd_seq_autoload_init(void) +{ + atomic_dec(&snd_seq_in_init); +#ifdef CONFIG_SND_SEQUENCER_MODULE + /* initial autoload only when snd-seq is a module */ + queue_autoload_drivers(); +#endif +} +#else +#define try_autoload(ops) /* NOP */ +#endif + +void snd_seq_device_load_drivers(void) +{ +#ifdef CONFIG_MODULES + queue_autoload_drivers(); + flush_work(&autoload_work); #endif } @@ -214,13 +255,14 @@ int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize, ops->num_devices++; mutex_unlock(&ops->reg_mutex); - unlock_driver(ops); - if ((err = snd_device_new(card, SNDRV_DEV_SEQUENCER, dev, &dops)) < 0) { snd_seq_device_free(dev); return err; } + try_autoload(ops); + unlock_driver(ops); + if (result) *result = dev; @@ -554,6 +596,9 @@ static int __init alsa_seq_device_init(void) static void __exit alsa_seq_device_exit(void) { +#ifdef CONFIG_MODULES + cancel_work_sync(&autoload_work); +#endif remove_drivers(); #ifdef CONFIG_PROC_FS snd_info_free_entry(info_entry); @@ -570,6 +615,7 @@ EXPORT_SYMBOL(snd_seq_device_new); EXPORT_SYMBOL(snd_seq_device_register_driver); EXPORT_SYMBOL(snd_seq_device_unregister_driver); #ifdef CONFIG_MODULES +EXPORT_SYMBOL(snd_seq_autoload_init); EXPORT_SYMBOL(snd_seq_autoload_lock); EXPORT_SYMBOL(snd_seq_autoload_unlock); #endif -- cgit v1.2.3 From d5129f33a0d155d69cb0652cfc87bbc4d132ca17 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 15 Oct 2014 14:09:42 +0200 Subject: Subject: ALSA: seq: Remove autoload locks in driver registration Since we're calling request_module() asynchronously now, we can get rid of the autoload lock in snd_seq_device_register_driver(), as well as in the snd-seq driver registration itself. This enables the automatic loading of dependent sequencer modules, such as snd-seq-virmidi from snd-emu10k1-synth. Signed-off-by: Takashi Iwai --- sound/core/seq/seq.c | 2 -- sound/core/seq/seq_device.c | 7 +------ 2 files changed, 1 insertion(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/core/seq/seq.c b/sound/core/seq/seq.c index bebdd2e920ca..7e0aabb808a6 100644 --- a/sound/core/seq/seq.c +++ b/sound/core/seq/seq.c @@ -86,7 +86,6 @@ static int __init alsa_seq_init(void) { int err; - snd_seq_autoload_lock(); if ((err = client_init_data()) < 0) goto error; @@ -112,7 +111,6 @@ static int __init alsa_seq_init(void) snd_seq_autoload_init(); error: - snd_seq_autoload_unlock(); return err; } diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c index a8e2c6016800..0631bdadd12b 100644 --- a/sound/core/seq/seq_device.c +++ b/sound/core/seq/seq_device.c @@ -360,16 +360,12 @@ int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry, entry->init_device == NULL || entry->free_device == NULL) return -EINVAL; - snd_seq_autoload_lock(); ops = find_driver(id, 1); - if (ops == NULL) { - snd_seq_autoload_unlock(); + if (ops == NULL) return -ENOMEM; - } if (ops->driver & DRIVER_LOADED) { pr_warn("ALSA: seq: driver_register: driver '%s' already exists\n", id); unlock_driver(ops); - snd_seq_autoload_unlock(); return -EBUSY; } @@ -386,7 +382,6 @@ int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry, mutex_unlock(&ops->reg_mutex); unlock_driver(ops); - snd_seq_autoload_unlock(); return 0; } -- cgit v1.2.3 From 49fd46d2ffc92de3f4bd2e337f60b8b6052dc8b6 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Sun, 19 Oct 2014 09:11:25 +0200 Subject: ALSA: snd-usb: drop unused varible assigments Don't assign 'len' in cases where we don't make use of the returned value. Signed-off-by: Daniel Mack Signed-off-by: Takashi Iwai --- sound/usb/mixer.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 2e4a9dbc51fa..63a8adb1705e 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -1290,9 +1290,8 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, kctl->id.name, sizeof(kctl->id.name), 1); if (!len) - len = snprintf(kctl->id.name, - sizeof(kctl->id.name), - "Feature %d", unitid); + snprintf(kctl->id.name, sizeof(kctl->id.name), + "Feature %d", unitid); } if (!mapped_name) @@ -1305,9 +1304,9 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, */ if (!mapped_name && !(state->oterm.type >> 16)) { if ((state->oterm.type & 0xff00) == 0x0100) - len = append_ctl_name(kctl, " Capture"); + append_ctl_name(kctl, " Capture"); else - len = append_ctl_name(kctl, " Playback"); + append_ctl_name(kctl, " Playback"); } append_ctl_name(kctl, control == UAC_FU_MUTE ? " Switch" : " Volume"); -- cgit v1.2.3 From 03ad6a8c93b6df2d65c305b5b5f9474068b45bfb Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Thu, 16 Oct 2014 15:33:45 +0200 Subject: ALSA: hda - Fix "PCM" name being used on one DAC when there are two DACs In the scenario where there is one "Line Out", one "Speaker" and one "Headphone", and there are only two DACs, two outputs will share a DAC. Currently any mixer on such a DAC will get the "PCM" name, which is misleading. Instead use "Headphone+LO" or "Speaker+LO" to better specify what the volume actually controls. [fixed missing slave string additions by tiwai] Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_generic.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 64220c08bd98..dc13cce70932 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -1038,6 +1038,19 @@ static const char *get_line_out_pfx(struct hda_codec *codec, int ch, break; *index = ch; return "Headphone"; + case AUTO_PIN_LINE_OUT: + /* This deals with the case where we have two DACs and + * one LO, one HP and one Speaker */ + if (!ch && cfg->speaker_outs && cfg->hp_outs) { + bool hp_lo_shared = !path_has_mixer(codec, spec->hp_paths[0], ctl_type); + bool spk_lo_shared = !path_has_mixer(codec, spec->speaker_paths[0], ctl_type); + if (hp_lo_shared && spk_lo_shared) + return spec->vmaster_mute.hook ? "PCM" : "Master"; + if (hp_lo_shared) + return "Headphone+LO"; + if (spk_lo_shared) + return "Speaker+LO"; + } } /* for a single channel output, we don't have to name the channel */ @@ -4524,7 +4537,7 @@ static const char * const slave_pfxs[] = { "CLFE", "Bass Speaker", "PCM", "Speaker Front", "Speaker Surround", "Speaker CLFE", "Speaker Side", "Headphone Front", "Headphone Surround", "Headphone CLFE", - "Headphone Side", + "Headphone Side", "Headphone+LO", "Speaker+LO", NULL, }; -- cgit v1.2.3 From 3abb4f4d0e7aaad0d12004b5057f4486a688752b Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Thu, 16 Oct 2014 15:33:46 +0200 Subject: ALSA: hda - Use "Line Out" name instead of "PCM" when there are other outputs In case there are speakers or headphones as well, anything that only covers the line out should not be labelled "PCM". Let's name it "Line Out" instead for clarity. Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_generic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index dc13cce70932..06d721085e72 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -1055,7 +1055,7 @@ static const char *get_line_out_pfx(struct hda_codec *codec, int ch, /* for a single channel output, we don't have to name the channel */ if (cfg->line_outs == 1 && !spec->multi_ios) - return "PCM"; + return "Line Out"; if (ch >= ARRAY_SIZE(channel_name)) { snd_BUG(); -- cgit v1.2.3 From df803e1389716bcdf11932fff47d7f1fc198bc8a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:07:21 +0200 Subject: ALSA: control: Warn if too long string is passed to snd_ctl_enum_info() This allows us to catch the bugs in drivers easily. Signed-off-by: Takashi Iwai --- sound/core/control.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/core/control.c b/sound/core/control.c index b9611344ff9e..f95df84437e1 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1747,6 +1747,9 @@ int snd_ctl_enum_info(struct snd_ctl_elem_info *info, unsigned int channels, info->value.enumerated.items = items; if (info->value.enumerated.item >= items) info->value.enumerated.item = items - 1; + WARN(strlen(names[info->value.enumerated.item]) >= sizeof(info->value.enumerated.name), + "ALSA: too long item name '%s'\n", + names[info->value.enumerated.item]); strlcpy(info->value.enumerated.name, names[info->value.enumerated.item], sizeof(info->value.enumerated.name)); -- cgit v1.2.3 From a7e6fb99150ebb2852ebd0e7bad9ce37cc9a79dd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:08:50 +0200 Subject: ALSA: control: Allow to pass items zero to snd_ctl_enum_info() Although this is weird, some drivers want to allow empty control elements intentionally, e.g. the number of items may change depending on the firmware status. Let the function simply returning in such a case. Signed-off-by: Takashi Iwai --- sound/core/control.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/core/control.c b/sound/core/control.c index f95df84437e1..5c35bbaf881e 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1745,6 +1745,8 @@ int snd_ctl_enum_info(struct snd_ctl_elem_info *info, unsigned int channels, info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; info->count = channels; info->value.enumerated.items = items; + if (!items) + return 0; if (info->value.enumerated.item >= items) info->value.enumerated.item = items - 1; WARN(strlen(names[info->value.enumerated.item]) >= sizeof(info->value.enumerated.name), -- cgit v1.2.3 From 04eeb606a8383b306f4bc6991da8231b5f3924b0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:10:39 +0200 Subject: ALSA: aoa: Use snd_ctl_elem_info() ... and reduce the open codes. Also add missing const to text arrays. Signed-off-by: Takashi Iwai --- sound/aoa/codecs/onyx.c | 8 +------- sound/aoa/codecs/tas.c | 10 ++-------- 2 files changed, 3 insertions(+), 15 deletions(-) (limited to 'sound') diff --git a/sound/aoa/codecs/onyx.c b/sound/aoa/codecs/onyx.c index 401107b85d30..23c371ecfb6b 100644 --- a/sound/aoa/codecs/onyx.c +++ b/sound/aoa/codecs/onyx.c @@ -243,13 +243,7 @@ static int onyx_snd_capture_source_info(struct snd_kcontrol *kcontrol, { static const char * const texts[] = { "Line-In", "Microphone" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item > 1) - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 2, texts); } static int onyx_snd_capture_source_get(struct snd_kcontrol *kcontrol, diff --git a/sound/aoa/codecs/tas.c b/sound/aoa/codecs/tas.c index cf3c6303b7e3..364c7c4416e8 100644 --- a/sound/aoa/codecs/tas.c +++ b/sound/aoa/codecs/tas.c @@ -478,15 +478,9 @@ static struct snd_kcontrol_new drc_switch_control = { static int tas_snd_capture_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "Line-In", "Microphone" }; + static const char * const texts[] = { "Line-In", "Microphone" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item > 1) - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 2, texts); } static int tas_snd_capture_source_get(struct snd_kcontrol *kcontrol, -- cgit v1.2.3 From 6d416f594bf9a290406d267e2627c5286f51ea59 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:11:28 +0200 Subject: ALSA: mts64: Use snd_ctl_elem_info() ... and reduce the open codes. Also add missing const to the text array. Signed-off-by: Takashi Iwai --- sound/drivers/mts64.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/drivers/mts64.c b/sound/drivers/mts64.c index f5fd448dbc57..0388fbbd2c06 100644 --- a/sound/drivers/mts64.c +++ b/sound/drivers/mts64.c @@ -604,21 +604,11 @@ static struct snd_kcontrol_new mts64_ctl_smpte_time_frames = { static int snd_mts64_ctl_smpte_fps_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) { - static char *texts[5] = { "24", - "25", - "29.97", - "30D", - "30" }; + static const char * const texts[5] = { + "24", "25", "29.97", "30D", "30" + }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 5; - if (uinfo->value.enumerated.item > 4) - uinfo->value.enumerated.item = 4; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - - return 0; + return snd_ctl_enum_info(uinfo, 1, 5, texts); } static int snd_mts64_ctl_smpte_fps_get(struct snd_kcontrol *kctl, -- cgit v1.2.3 From 7f471fd40742a5d87d887375430bf40331cbbcf6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:11:58 +0200 Subject: ALSA: vx: Use snd_ctl_elem_info() ... and reduce the open codes. Also add missing const to text arrays. Signed-off-by: Takashi Iwai --- sound/drivers/vx/vx_mixer.c | 35 ++++++++--------------------------- 1 file changed, 8 insertions(+), 27 deletions(-) (limited to 'sound') diff --git a/sound/drivers/vx/vx_mixer.c b/sound/drivers/vx/vx_mixer.c index 3b6823fc0606..be9477e30739 100644 --- a/sound/drivers/vx/vx_mixer.c +++ b/sound/drivers/vx/vx_mixer.c @@ -471,30 +471,18 @@ static struct snd_kcontrol_new vx_control_output_level = { */ static int vx_audio_src_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts_mic[3] = { + static const char * const texts_mic[3] = { "Digital", "Line", "Mic" }; - static char *texts_vx2[2] = { + static const char * const texts_vx2[2] = { "Digital", "Analog" }; struct vx_core *chip = snd_kcontrol_chip(kcontrol); - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - if (chip->type >= VX_TYPE_VXPOCKET) { - uinfo->value.enumerated.items = 3; - if (uinfo->value.enumerated.item > 2) - uinfo->value.enumerated.item = 2; - strcpy(uinfo->value.enumerated.name, - texts_mic[uinfo->value.enumerated.item]); - } else { - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item > 1) - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, - texts_vx2[uinfo->value.enumerated.item]); - } - return 0; + if (chip->type >= VX_TYPE_VXPOCKET) + return snd_ctl_enum_info(uinfo, 1, 3, texts_mic); + else + return snd_ctl_enum_info(uinfo, 1, 2, texts_vx2); } static int vx_audio_src_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -539,18 +527,11 @@ static struct snd_kcontrol_new vx_control_audio_src = { */ static int vx_clock_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[3] = { + static const char * const texts[3] = { "Auto", "Internal", "External" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - if (uinfo->value.enumerated.item > 2) - uinfo->value.enumerated.item = 2; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 3, texts); } static int vx_clock_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -- cgit v1.2.3 From e7ced4137d859c576130ce7605e5fdd13221793d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 21 Oct 2014 08:26:10 +0200 Subject: ALSA: bebob: More constify text arrays Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob.h | 4 ++-- sound/firewire/bebob/bebob_focusrite.c | 10 +++++----- sound/firewire/bebob/bebob_maudio.c | 18 +++++++++--------- sound/firewire/bebob/bebob_terratec.c | 4 ++-- sound/firewire/bebob/bebob_yamaha.c | 2 +- 5 files changed, 19 insertions(+), 19 deletions(-) (limited to 'sound') diff --git a/sound/firewire/bebob/bebob.h b/sound/firewire/bebob/bebob.h index e13eef99c27a..dfbcd233178c 100644 --- a/sound/firewire/bebob/bebob.h +++ b/sound/firewire/bebob/bebob.h @@ -52,7 +52,7 @@ extern const unsigned int snd_bebob_rate_table[SND_BEBOB_STRM_FMT_ENTRIES]; #define SND_BEBOB_CLOCK_INTERNAL "Internal" struct snd_bebob_clock_spec { unsigned int num; - char *const *labels; + const char *const *labels; int (*get)(struct snd_bebob *bebob, unsigned int *id); }; struct snd_bebob_rate_spec { @@ -61,7 +61,7 @@ struct snd_bebob_rate_spec { }; struct snd_bebob_meter_spec { unsigned int num; - char *const *labels; + const char *const *labels; int (*get)(struct snd_bebob *bebob, u32 *target, unsigned int size); }; struct snd_bebob_spec { diff --git a/sound/firewire/bebob/bebob_focusrite.c b/sound/firewire/bebob/bebob_focusrite.c index 45a0eed6d5b1..a45a86952a41 100644 --- a/sound/firewire/bebob/bebob_focusrite.c +++ b/sound/firewire/bebob/bebob_focusrite.c @@ -101,11 +101,11 @@ saffire_write_quad(struct snd_bebob *bebob, u64 offset, u32 value) &data, sizeof(__be32), 0); } -static char *const saffirepro_26_clk_src_labels[] = { +static const char *const saffirepro_26_clk_src_labels[] = { SND_BEBOB_CLOCK_INTERNAL, "S/PDIF", "ADAT1", "ADAT2", "Word Clock" }; -static char *const saffirepro_10_clk_src_labels[] = { +static const char *const saffirepro_10_clk_src_labels[] = { SND_BEBOB_CLOCK_INTERNAL, "S/PDIF", "Word Clock" }; static int @@ -161,7 +161,7 @@ end: } struct snd_bebob_spec saffire_le_spec; -static char *const saffire_both_clk_src_labels[] = { +static const char *const saffire_both_clk_src_labels[] = { SND_BEBOB_CLOCK_INTERNAL, "S/PDIF" }; static int @@ -176,12 +176,12 @@ saffire_both_clk_src_get(struct snd_bebob *bebob, unsigned int *id) return err; }; -static char *const saffire_le_meter_labels[] = { +static const char *const saffire_le_meter_labels[] = { ANA_IN, ANA_IN, DIG_IN, ANA_OUT, ANA_OUT, ANA_OUT, ANA_OUT, STM_IN, STM_IN }; -static char *const saffire_meter_labels[] = { +static const char *const saffire_meter_labels[] = { ANA_IN, ANA_IN, STM_IN, STM_IN, STM_IN, STM_IN, STM_IN, }; diff --git a/sound/firewire/bebob/bebob_maudio.c b/sound/firewire/bebob/bebob_maudio.c index 70faa3a32526..34cba8037b36 100644 --- a/sound/firewire/bebob/bebob_maudio.c +++ b/sound/firewire/bebob/bebob_maudio.c @@ -340,7 +340,7 @@ end: } /* Clock source control for special firmware */ -static char *const special_clk_labels[] = { +static const char *const special_clk_labels[] = { SND_BEBOB_CLOCK_INTERNAL " with Digital Mute", "Digital", "Word Clock", SND_BEBOB_CLOCK_INTERNAL}; static int special_clk_get(struct snd_bebob *bebob, unsigned int *id) @@ -438,7 +438,7 @@ static struct snd_kcontrol_new special_sync_ctl = { }; /* Digital input interface control for special firmware */ -static char *const special_dig_in_iface_labels[] = { +static const char *const special_dig_in_iface_labels[] = { "S/PDIF Optical", "S/PDIF Coaxial", "ADAT Optical" }; static int special_dig_in_iface_ctl_info(struct snd_kcontrol *kctl, @@ -539,7 +539,7 @@ static struct snd_kcontrol_new special_dig_in_iface_ctl = { }; /* Digital output interface control for special firmware */ -static char *const special_dig_out_iface_labels[] = { +static const char *const special_dig_out_iface_labels[] = { "S/PDIF Optical and Coaxial", "ADAT Optical" }; static int special_dig_out_iface_ctl_info(struct snd_kcontrol *kctl, @@ -631,7 +631,7 @@ end: } /* Hardware metering for special firmware */ -static char *const special_meter_labels[] = { +static const char *const special_meter_labels[] = { ANA_IN, ANA_IN, ANA_IN, ANA_IN, SPDIF_IN, ADAT_IN, ADAT_IN, ADAT_IN, ADAT_IN, @@ -671,30 +671,30 @@ end: } /* last 4 bytes are omitted because it's clock info. */ -static char *const fw410_meter_labels[] = { +static const char *const fw410_meter_labels[] = { ANA_IN, DIG_IN, ANA_OUT, ANA_OUT, ANA_OUT, ANA_OUT, DIG_OUT, HP_OUT }; -static char *const audiophile_meter_labels[] = { +static const char *const audiophile_meter_labels[] = { ANA_IN, DIG_IN, ANA_OUT, ANA_OUT, DIG_OUT, HP_OUT, AUX_OUT, }; -static char *const solo_meter_labels[] = { +static const char *const solo_meter_labels[] = { ANA_IN, DIG_IN, STRM_IN, STRM_IN, ANA_OUT, DIG_OUT }; /* no clock info */ -static char *const ozonic_meter_labels[] = { +static const char *const ozonic_meter_labels[] = { ANA_IN, ANA_IN, STRM_IN, STRM_IN, ANA_OUT, ANA_OUT }; /* TODO: need testers. these positions are based on authour's assumption */ -static char *const nrv10_meter_labels[] = { +static const char *const nrv10_meter_labels[] = { ANA_IN, ANA_IN, ANA_IN, ANA_IN, DIG_IN, ANA_OUT, ANA_OUT, ANA_OUT, ANA_OUT, diff --git a/sound/firewire/bebob/bebob_terratec.c b/sound/firewire/bebob/bebob_terratec.c index 0e4c0bfc463b..83b677224f1f 100644 --- a/sound/firewire/bebob/bebob_terratec.c +++ b/sound/firewire/bebob/bebob_terratec.c @@ -8,7 +8,7 @@ #include "./bebob.h" -static char *const phase88_rack_clk_src_labels[] = { +static const char *const phase88_rack_clk_src_labels[] = { SND_BEBOB_CLOCK_INTERNAL, "Digital In", "Word Clock" }; static int @@ -29,7 +29,7 @@ end: return err; } -static char *const phase24_series_clk_src_labels[] = { +static const char *const phase24_series_clk_src_labels[] = { SND_BEBOB_CLOCK_INTERNAL, "Digital In" }; static int diff --git a/sound/firewire/bebob/bebob_yamaha.c b/sound/firewire/bebob/bebob_yamaha.c index 9b7e798180ff..ef1fe3823a9c 100644 --- a/sound/firewire/bebob/bebob_yamaha.c +++ b/sound/firewire/bebob/bebob_yamaha.c @@ -28,7 +28,7 @@ * reccomend users to close ffado-mixer at 192.0kHz if mixer is needless. */ -static char *const clk_src_labels[] = {SND_BEBOB_CLOCK_INTERNAL, "SPDIF"}; +static const char *const clk_src_labels[] = {SND_BEBOB_CLOCK_INTERNAL, "SPDIF"}; static int clk_src_get(struct snd_bebob *bebob, unsigned int *id) { -- cgit v1.2.3 From 41be5164ea09c92d551e8007d2543418e40f847a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:12:26 +0200 Subject: ALSA: bebob: Use snd_ctl_enum_info() ... and reduce the open codes. Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob_maudio.c | 41 ++++++++----------------------------- 1 file changed, 8 insertions(+), 33 deletions(-) (limited to 'sound') diff --git a/sound/firewire/bebob/bebob_maudio.c b/sound/firewire/bebob/bebob_maudio.c index 34cba8037b36..a422aaa3bb0c 100644 --- a/sound/firewire/bebob/bebob_maudio.c +++ b/sound/firewire/bebob/bebob_maudio.c @@ -352,17 +352,8 @@ static int special_clk_get(struct snd_bebob *bebob, unsigned int *id) static int special_clk_ctl_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *einf) { - einf->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - einf->count = 1; - einf->value.enumerated.items = ARRAY_SIZE(special_clk_labels); - - if (einf->value.enumerated.item >= einf->value.enumerated.items) - einf->value.enumerated.item = einf->value.enumerated.items - 1; - - strcpy(einf->value.enumerated.name, - special_clk_labels[einf->value.enumerated.item]); - - return 0; + return snd_ctl_enum_info(einf, 1, ARRAY_SIZE(special_clk_labels), + special_clk_labels); } static int special_clk_ctl_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uval) @@ -444,17 +435,9 @@ static const char *const special_dig_in_iface_labels[] = { static int special_dig_in_iface_ctl_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *einf) { - einf->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - einf->count = 1; - einf->value.enumerated.items = ARRAY_SIZE(special_dig_in_iface_labels); - - if (einf->value.enumerated.item >= einf->value.enumerated.items) - einf->value.enumerated.item = einf->value.enumerated.items - 1; - - strcpy(einf->value.enumerated.name, - special_dig_in_iface_labels[einf->value.enumerated.item]); - - return 0; + return snd_ctl_enum_info(einf, 1, + ARRAY_SIZE(special_dig_in_iface_labels), + special_dig_in_iface_labels); } static int special_dig_in_iface_ctl_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uval) @@ -545,17 +528,9 @@ static const char *const special_dig_out_iface_labels[] = { static int special_dig_out_iface_ctl_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *einf) { - einf->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - einf->count = 1; - einf->value.enumerated.items = ARRAY_SIZE(special_dig_out_iface_labels); - - if (einf->value.enumerated.item >= einf->value.enumerated.items) - einf->value.enumerated.item = einf->value.enumerated.items - 1; - - strcpy(einf->value.enumerated.name, - special_dig_out_iface_labels[einf->value.enumerated.item]); - - return 0; + return snd_ctl_enum_info(einf, 1, + ARRAY_SIZE(special_dig_out_iface_labels), + special_dig_out_iface_labels); } static int special_dig_out_iface_ctl_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uval) -- cgit v1.2.3 From 609e478b40aceaa07d14f1bada02a3874bac2c45 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:13:01 +0200 Subject: ALSA: ak4xxx-adda: Use snd_ctl_enum_info() ... and reduce the open codes. Also add missing const to the text array. Signed-off-by: Takashi Iwai --- sound/i2c/other/ak4xxx-adda.c | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) (limited to 'sound') diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c index f3735e64791c..67dbfde837ab 100644 --- a/sound/i2c/other/ak4xxx-adda.c +++ b/sound/i2c/other/ak4xxx-adda.c @@ -465,17 +465,10 @@ static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol, static int snd_akm4xxx_deemphasis_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[4] = { + static const char * const texts[4] = { "44.1kHz", "Off", "48kHz", "32kHz", }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 4; - if (uinfo->value.enumerated.item >= 4) - uinfo->value.enumerated.item = 3; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 4, texts); } static int snd_akm4xxx_deemphasis_get(struct snd_kcontrol *kcontrol, @@ -570,22 +563,13 @@ static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol, { struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); int mixer_ch = AK_GET_SHIFT(kcontrol->private_value); - const char **input_names; - unsigned int num_names, idx; + unsigned int num_names; num_names = ak4xxx_capture_num_inputs(ak, mixer_ch); if (!num_names) return -EINVAL; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = num_names; - idx = uinfo->value.enumerated.item; - if (idx >= num_names) - return -EINVAL; - input_names = ak->adc_info[mixer_ch].input_names; - strlcpy(uinfo->value.enumerated.name, input_names[idx], - sizeof(uinfo->value.enumerated.name)); - return 0; + return snd_ctl_enum_info(uinfo, 1, num_names, + ak->adc_info[mixer_ch].input_names); } static int ak4xxx_capture_source_get(struct snd_kcontrol *kcontrol, -- cgit v1.2.3 From 1da0c47779840d038583ea6fa4e3497939d6ea21 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:13:39 +0200 Subject: ALSA: ad1816a: Use snd_ctl_enum_info() ... and reduce the open codes. Also add missing const to the text array. Signed-off-by: Takashi Iwai --- sound/isa/ad1816a/ad1816a_lib.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c index f0fd98e695e3..01a07986f4a3 100644 --- a/sound/isa/ad1816a/ad1816a_lib.c +++ b/sound/isa/ad1816a/ad1816a_lib.c @@ -731,18 +731,12 @@ int snd_ad1816a_timer(struct snd_ad1816a *chip, int device, static int snd_ad1816a_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[8] = { + static const char * const texts[8] = { "Line", "Mix", "CD", "Synth", "Video", "Mic", "Phone", }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 2; - uinfo->value.enumerated.items = 7; - if (uinfo->value.enumerated.item > 6) - uinfo->value.enumerated.item = 6; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 2, 7, texts); } static int snd_ad1816a_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -- cgit v1.2.3 From 69b0c762cfd4c5e86a5b1fc0074889881b859c4a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:14:07 +0200 Subject: ALSA: es1688: Use snd_ctl_enum_info() ... and reduce the open codes. Also correct the array size and add missing const. Signed-off-by: Takashi Iwai --- sound/isa/es1688/es1688_lib.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c index b3b4f15e45ba..de810e484bdf 100644 --- a/sound/isa/es1688/es1688_lib.c +++ b/sound/isa/es1688/es1688_lib.c @@ -762,18 +762,12 @@ int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip, static int snd_es1688_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[9] = { + static const char * const texts[8] = { "Mic", "Mic Master", "CD", "AOUT", "Mic1", "Mix", "Line", "Master" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 8; - if (uinfo->value.enumerated.item > 7) - uinfo->value.enumerated.item = 7; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 8, texts); } static int snd_es1688_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -- cgit v1.2.3 From 4e28350a8c54a8b873b610311eb384a619c4045b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:14:24 +0200 Subject: ALSA: es18xx: Use snd_ctl_enum_info() ... and reduce the open codes. Also add missing const to text arrays. Signed-off-by: Takashi Iwai --- sound/isa/es18xx.c | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) (limited to 'sound') diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index 6faaac60161a..63e7323e218f 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c @@ -964,44 +964,28 @@ static int snd_es18xx_capture_close(struct snd_pcm_substream *substream) static int snd_es18xx_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts5Source[5] = { + static const char * const texts5Source[5] = { "Mic", "CD", "Line", "Master", "Mix" }; - static char *texts8Source[8] = { + static const char * const texts8Source[8] = { "Mic", "Mic Master", "CD", "AOUT", "Mic1", "Mix", "Line", "Master" }; struct snd_es18xx *chip = snd_kcontrol_chip(kcontrol); - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; switch (chip->version) { case 0x1868: case 0x1878: - uinfo->value.enumerated.items = 4; - if (uinfo->value.enumerated.item > 3) - uinfo->value.enumerated.item = 3; - strcpy(uinfo->value.enumerated.name, - texts5Source[uinfo->value.enumerated.item]); - break; + return snd_ctl_enum_info(uinfo, 1, 4, texts5Source); case 0x1887: case 0x1888: - uinfo->value.enumerated.items = 5; - if (uinfo->value.enumerated.item > 4) - uinfo->value.enumerated.item = 4; - strcpy(uinfo->value.enumerated.name, texts5Source[uinfo->value.enumerated.item]); - break; + return snd_ctl_enum_info(uinfo, 1, 5, texts5Source); case 0x1869: /* DS somewhat contradictory for 1869: could be be 5 or 8 */ case 0x1879: - uinfo->value.enumerated.items = 8; - if (uinfo->value.enumerated.item > 7) - uinfo->value.enumerated.item = 7; - strcpy(uinfo->value.enumerated.name, texts8Source[uinfo->value.enumerated.item]); - break; + return snd_ctl_enum_info(uinfo, 1, 8, texts8Source); default: return -EINVAL; } - return 0; } static int snd_es18xx_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -- cgit v1.2.3 From 8edd2d120b6821d6eba9fedd0b17b7a47fbe9181 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:14:41 +0200 Subject: ALSA: msnd: Use snd_ctl_enum_info() ... and reduce the open codes. Also add missing const to the text array. Signed-off-by: Takashi Iwai --- sound/isa/msnd/msnd_pinnacle_mixer.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/isa/msnd/msnd_pinnacle_mixer.c b/sound/isa/msnd/msnd_pinnacle_mixer.c index 031dc69b7470..17e49a071af4 100644 --- a/sound/isa/msnd/msnd_pinnacle_mixer.c +++ b/sound/isa/msnd/msnd_pinnacle_mixer.c @@ -55,20 +55,13 @@ static int snd_msndmix_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[3] = { + static const char * const texts[3] = { "Analog", "MASS", "SPDIF", }; struct snd_msnd *chip = snd_kcontrol_chip(kcontrol); unsigned items = test_bit(F_HAVEDIGITAL, &chip->flags) ? 3 : 2; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = items; - if (uinfo->value.enumerated.item >= items) - uinfo->value.enumerated.item = items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, items, texts); } static int snd_msndmix_get_mux(struct snd_kcontrol *kcontrol, -- cgit v1.2.3 From 6b9e1288a506b4d10c48a67058532c52c5c46240 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:14:51 +0200 Subject: ALSA: sb16: Use snd_ctl_enum_info() ... and reduce the open codes. Also add missing const to text arrays. Signed-off-by: Takashi Iwai --- sound/isa/sb/sb16_main.c | 10 ++-------- sound/isa/sb/sb_mixer.c | 31 ++++++------------------------- 2 files changed, 8 insertions(+), 33 deletions(-) (limited to 'sound') diff --git a/sound/isa/sb/sb16_main.c b/sound/isa/sb/sb16_main.c index 0bbcd4714d28..72b10f4f3e70 100644 --- a/sound/isa/sb/sb16_main.c +++ b/sound/isa/sb/sb16_main.c @@ -702,17 +702,11 @@ static int snd_sb16_get_dma_mode(struct snd_sb *chip) static int snd_sb16_dma_control_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[3] = { + static const char * const texts[3] = { "Auto", "Playback", "Capture" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - if (uinfo->value.enumerated.item > 2) - uinfo->value.enumerated.item = 2; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 3, texts); } static int snd_sb16_dma_control_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c index 1ff78ec9f0ac..e403334a19ad 100644 --- a/sound/isa/sb/sb_mixer.c +++ b/sound/isa/sb/sb_mixer.c @@ -182,17 +182,11 @@ static int snd_sbmixer_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_ static int snd_dt019x_input_sw_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static const char *texts[5] = { + static const char * const texts[5] = { "CD", "Mic", "Line", "Synth", "Master" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 5; - if (uinfo->value.enumerated.item > 4) - uinfo->value.enumerated.item = 4; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 5, texts); } static int snd_dt019x_input_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -275,18 +269,11 @@ static int snd_dt019x_input_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl static int snd_als4k_mono_capture_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static const char *texts[3] = { + static const char * const texts[3] = { "L chan only", "R chan only", "L ch/2 + R ch/2" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - if (uinfo->value.enumerated.item > 2) - uinfo->value.enumerated.item = 2; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 3, texts); } static int snd_als4k_mono_capture_route_get(struct snd_kcontrol *kcontrol, @@ -335,17 +322,11 @@ static int snd_als4k_mono_capture_route_put(struct snd_kcontrol *kcontrol, static int snd_sb8mixer_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static const char *texts[3] = { + static const char * const texts[3] = { "Mic", "CD", "Line" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - if (uinfo->value.enumerated.item > 2) - uinfo->value.enumerated.item = 2; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 3, texts); } -- cgit v1.2.3 From 0773efa53260a57d6e3bc38469c216635700537e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:15:06 +0200 Subject: ALSA: wss: Use snd_ctl_enum_info() ... and reduce the open codes. Also add missing const to text arrays. Signed-off-by: Takashi Iwai --- sound/isa/wss/wss_lib.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c index 360b08b03e1d..347bb1bda110 100644 --- a/sound/isa/wss/wss_lib.c +++ b/sound/isa/wss/wss_lib.c @@ -1993,25 +1993,20 @@ EXPORT_SYMBOL(snd_wss_timer); static int snd_wss_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[4] = { + static const char * const texts[4] = { "Line", "Aux", "Mic", "Mix" }; - static char *opl3sa_texts[4] = { + static const char * const opl3sa_texts[4] = { "Line", "CD", "Mic", "Mix" }; - static char *gusmax_texts[4] = { + static const char * const gusmax_texts[4] = { "Line", "Synth", "Mic", "Mix" }; - char **ptexts = texts; + const char * const *ptexts = texts; struct snd_wss *chip = snd_kcontrol_chip(kcontrol); if (snd_BUG_ON(!chip->card)) return -EINVAL; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 2; - uinfo->value.enumerated.items = 4; - if (uinfo->value.enumerated.item > 3) - uinfo->value.enumerated.item = 3; if (!strcmp(chip->card->driver, "GUS MAX")) ptexts = gusmax_texts; switch (chip->hardware) { @@ -2023,8 +2018,7 @@ static int snd_wss_info_mux(struct snd_kcontrol *kcontrol, ptexts = opl3sa_texts; break; } - strcpy(uinfo->value.enumerated.name, ptexts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 2, 4, ptexts); } static int snd_wss_get_mux(struct snd_kcontrol *kcontrol, -- cgit v1.2.3 From 2a2085ab198439c8f08be2f6b9b5cbc9e93877b7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:15:16 +0200 Subject: ALSA: mips: Use snd_ctl_enum_info() ... and reduce the open codes. Also add missing const to the text array. Signed-off-by: Takashi Iwai --- sound/mips/sgio2audio.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/mips/sgio2audio.c b/sound/mips/sgio2audio.c index 04bb06c03ec8..33b08fcc27a9 100644 --- a/sound/mips/sgio2audio.c +++ b/sound/mips/sgio2audio.c @@ -201,17 +201,10 @@ static int sgio2audio_gain_put(struct snd_kcontrol *kcontrol, static int sgio2audio_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static const char *texts[3] = { + static const char * const texts[3] = { "Cam Mic", "Mic", "Line" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - if (uinfo->value.enumerated.item >= 3) - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 3, texts); } static int sgio2audio_source_get(struct snd_kcontrol *kcontrol, -- cgit v1.2.3 From 3c6a73cc6b6ccd9188b3405c744365c0874b9274 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:15:26 +0200 Subject: ALSA: parisc: Use snd_ctl_enum_info() ... and reduce the open codes. Also add missing const to the text array. Signed-off-by: Takashi Iwai --- sound/parisc/harmony.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/parisc/harmony.c b/sound/parisc/harmony.c index 4b20be79c1dd..29604a239c44 100644 --- a/sound/parisc/harmony.c +++ b/sound/parisc/harmony.c @@ -776,15 +776,9 @@ static int snd_harmony_captureroute_info(struct snd_kcontrol *kc, struct snd_ctl_elem_info *uinfo) { - static char *texts[2] = { "Line", "Mic" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item > 1) - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; + static const char * const texts[2] = { "Line", "Mic" }; + + return snd_ctl_enum_info(uinfo, 1, 2, texts); } static int -- cgit v1.2.3 From 3b7a00dc9e4277d6fcad68dd1db35f77264ede5f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:15:36 +0200 Subject: ALSA: ac97: Use snd_ctl_enum_info() ... and reduce the open codes. Also add missing const to text arrays. Signed-off-by: Takashi Iwai --- sound/pci/ac97/ac97_codec.c | 10 +-- sound/pci/ac97/ac97_patch.c | 176 +++++++++++++------------------------------- 2 files changed, 53 insertions(+), 133 deletions(-) (limited to 'sound') diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 14ad54b7928c..5ee2f17c287c 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -463,14 +463,8 @@ static int snd_ac97_info_enum_double(struct snd_kcontrol *kcontrol, { struct ac97_enum *e = (struct ac97_enum *)kcontrol->private_value; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = e->shift_l == e->shift_r ? 1 : 2; - uinfo->value.enumerated.items = e->mask; - - if (uinfo->value.enumerated.item > e->mask - 1) - uinfo->value.enumerated.item = e->mask - 1; - strcpy(uinfo->value.enumerated.name, e->texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, e->shift_l == e->shift_r ? 1 : 2, + e->mask, e->texts); } static int snd_ac97_get_enum_double(struct snd_kcontrol *kcontrol, diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 991762215417..50f420d69a8a 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -81,22 +81,11 @@ static int ac97_update_bits_page(struct snd_ac97 *ac97, unsigned short reg, unsi /* * shared line-in/mic controls */ -static int ac97_enum_text_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo, - const char **texts, unsigned int nums) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = nums; - if (uinfo->value.enumerated.item > nums - 1) - uinfo->value.enumerated.item = nums - 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; -} - static int ac97_surround_jack_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static const char *texts[] = { "Shared", "Independent" }; - return ac97_enum_text_info(kcontrol, uinfo, texts, 2); + static const char * const texts[] = { "Shared", "Independent" }; + + return snd_ctl_enum_info(uinfo, 1, 2, texts); } static int ac97_surround_jack_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -123,9 +112,9 @@ static int ac97_surround_jack_mode_put(struct snd_kcontrol *kcontrol, struct snd static int ac97_channel_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static const char *texts[] = { "2ch", "4ch", "6ch", "8ch" }; - return ac97_enum_text_info(kcontrol, uinfo, texts, - kcontrol->private_value); + static const char * const texts[] = { "2ch", "4ch", "6ch", "8ch" }; + + return snd_ctl_enum_info(uinfo, 1, kcontrol->private_value, texts); } static int ac97_channel_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -240,17 +229,11 @@ static inline int alc850_is_aux_back_surround(struct snd_ac97 *ac97) static int snd_ac97_ymf7x3_info_speaker(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[3] = { + static const char * const texts[3] = { "Standard", "Small", "Smaller" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - if (uinfo->value.enumerated.item > 2) - uinfo->value.enumerated.item = 2; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 3, texts); } static int snd_ac97_ymf7x3_get_speaker(struct snd_kcontrol *kcontrol, @@ -293,15 +276,9 @@ static const struct snd_kcontrol_new snd_ac97_ymf7x3_controls_speaker = static int snd_ac97_ymf7x3_spdif_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[2] = { "AC-Link", "A/D Converter" }; + static const char * const texts[2] = { "AC-Link", "A/D Converter" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item > 1) - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 2, texts); } static int snd_ac97_ymf7x3_spdif_source_get(struct snd_kcontrol *kcontrol, @@ -401,15 +378,9 @@ static int patch_yamaha_ymf743(struct snd_ac97 *ac97) There is also a bit to mute S/PDIF output in a vendor-specific register. */ static int snd_ac97_ymf753_spdif_output_pin_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[3] = { "Disabled", "Pin 43", "Pin 48" }; + static const char * const texts[3] = { "Disabled", "Pin 43", "Pin 48" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - if (uinfo->value.enumerated.item > 2) - uinfo->value.enumerated.item = 2; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 3, texts); } static int snd_ac97_ymf753_spdif_output_pin_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1103,16 +1074,11 @@ static int patch_sigmatel_stac9756(struct snd_ac97 * ac97) static int snd_ac97_stac9758_output_jack_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[5] = { "Input/Disabled", "Front Output", + static const char * const texts[5] = { + "Input/Disabled", "Front Output", "Rear Output", "Center/LFE Output", "Mixer Output" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 5; - if (uinfo->value.enumerated.item > 4) - uinfo->value.enumerated.item = 4; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 5, texts); } static int snd_ac97_stac9758_output_jack_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1147,16 +1113,11 @@ static int snd_ac97_stac9758_output_jack_put(struct snd_kcontrol *kcontrol, stru static int snd_ac97_stac9758_input_jack_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[7] = { "Mic2 Jack", "Mic1 Jack", "Line In Jack", + static const char * const texts[7] = { + "Mic2 Jack", "Mic1 Jack", "Line In Jack", "Front Jack", "Rear Jack", "Center/LFE Jack", "Mute" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 7; - if (uinfo->value.enumerated.item > 6) - uinfo->value.enumerated.item = 6; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 7, texts); } static int snd_ac97_stac9758_input_jack_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1181,15 +1142,11 @@ static int snd_ac97_stac9758_input_jack_put(struct snd_kcontrol *kcontrol, struc static int snd_ac97_stac9758_phonesel_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[3] = { "None", "Front Jack", "Rear Jack" }; + static const char * const texts[3] = { + "None", "Front Jack", "Rear Jack" + }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - if (uinfo->value.enumerated.item > 2) - uinfo->value.enumerated.item = 2; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 3, texts); } static int snd_ac97_stac9758_phonesel_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1804,15 +1761,9 @@ static int patch_ad1886(struct snd_ac97 * ac97) static int snd_ac97_ad198x_spdif_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[2] = { "AC-Link", "A/D Converter" }; + static const char * const texts[2] = { "AC-Link", "A/D Converter" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item > 1) - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 2, texts); } static int snd_ac97_ad198x_spdif_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1994,15 +1945,9 @@ static int snd_ac97_ad1888_lohpsel_put(struct snd_kcontrol *kcontrol, struct snd static int snd_ac97_ad1888_downmix_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[3] = {"Off", "6 -> 4", "6 -> 2"}; + static const char * const texts[3] = {"Off", "6 -> 4", "6 -> 2"}; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - if (uinfo->value.enumerated.item > 2) - uinfo->value.enumerated.item = 2; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 3, texts); } static int snd_ac97_ad1888_downmix_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -2153,16 +2098,11 @@ static int patch_ad1980(struct snd_ac97 * ac97) static int snd_ac97_ad1985_vrefout_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[4] = {"High-Z", "3.7 V", "2.25 V", "0 V"}; + static const char * const texts[4] = { + "High-Z", "3.7 V", "2.25 V", "0 V" + }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 4; - if (uinfo->value.enumerated.item > 3) - uinfo->value.enumerated.item = 3; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 4, texts); } static int snd_ac97_ad1985_vrefout_get(struct snd_kcontrol *kcontrol, @@ -2756,20 +2696,18 @@ static const struct snd_kcontrol_new snd_ac97_controls_alc655[] = { static int alc655_iec958_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts_655[3] = { "PCM", "Analog In", "IEC958 In" }; - static char *texts_658[4] = { "PCM", "Analog1 In", "Analog2 In", "IEC958 In" }; + static const char * const texts_655[3] = { + "PCM", "Analog In", "IEC958 In" + }; + static const char * const texts_658[4] = { + "PCM", "Analog1 In", "Analog2 In", "IEC958 In" + }; struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = ac97->spec.dev_flags ? 4 : 3; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - ac97->spec.dev_flags ? - texts_658[uinfo->value.enumerated.item] : - texts_655[uinfo->value.enumerated.item]); - return 0; + if (ac97->spec.dev_flags) + return snd_ctl_enum_info(uinfo, 1, 4, texts_658); + else + return snd_ctl_enum_info(uinfo, 1, 3, texts_655); } static int alc655_iec958_route_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -3055,15 +2993,9 @@ static int patch_cm9738(struct snd_ac97 * ac97) static int snd_ac97_cmedia_spdif_playback_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "Analog", "Digital" }; + static const char * const texts[] = { "Analog", "Digital" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item > 1) - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 2, texts); } static int snd_ac97_cmedia_spdif_playback_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -3235,15 +3167,9 @@ static const struct snd_kcontrol_new snd_ac97_cm9761_controls[] = { static int cm9761_spdif_out_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "AC-Link", "ADC", "SPDIF-In" }; + static const char * const texts[] = { "AC-Link", "ADC", "SPDIF-In" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - if (uinfo->value.enumerated.item > 2) - uinfo->value.enumerated.item = 2; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 3, texts); } static int cm9761_spdif_out_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -3552,11 +3478,12 @@ static int snd_ac97_vt1617a_smart51_info(struct snd_kcontrol *kcontrol, * is SM51EN *AND* it's Bit14, not Bit15 so the table is very * counter-intuitive */ - static const char* texts[] = { "LineIn Mic1", "LineIn Mic1 Mic3", + static const char * const texts[] = {"LineIn Mic1", "LineIn Mic1 Mic3", "Surr LFE/C Mic3", "LineIn LFE/C Mic3", "LineIn Mic2", "LineIn Mic2 Mic1", "Surr LFE Mic1", "Surr LFE Mic1 Mic2"}; - return ac97_enum_text_info(kcontrol, uinfo, texts, 8); + + return snd_ctl_enum_info(uinfo, 1, 8, texts); } static int snd_ac97_vt1617a_smart51_get(struct snd_kcontrol *kcontrol, @@ -3720,9 +3647,8 @@ static struct vt1618_uaj_item vt1618_uaj[3] = { static int snd_ac97_vt1618_UAJ_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - return ac97_enum_text_info(kcontrol, uinfo, - vt1618_uaj[kcontrol->private_value].items, - 4); + return snd_ctl_enum_info(uinfo, 1, 4, + vt1618_uaj[kcontrol->private_value].items); } /* All of the vt1618 Universal Audio Jack twiddlers are on @@ -3767,9 +3693,9 @@ static int snd_ac97_vt1618_UAJ_put(struct snd_kcontrol *kcontrol, static int snd_ac97_vt1618_aux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static const char *txt_aux[] = {"Aux In", "Back Surr Out"}; + static const char * const txt_aux[] = {"Aux In", "Back Surr Out"}; - return ac97_enum_text_info(kcontrol, uinfo, txt_aux, 2); + return snd_ctl_enum_info(uinfo, 1, 2, txt_aux); } static int snd_ac97_vt1618_aux_get(struct snd_kcontrol *kcontrol, -- cgit v1.2.3 From 1bc10bb68d348078af0eb8b64292ec542dcd7634 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 21 Oct 2014 08:51:45 +0200 Subject: ALSA: ac97: Constify more text arrays Signed-off-by: Takashi Iwai --- sound/pci/ac97/ac97_patch.c | 22 ++++++++++++++-------- sound/pci/ac97/ac97_patch.h | 2 +- 2 files changed, 15 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 50f420d69a8a..ceaac1c41906 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -33,7 +33,8 @@ static struct snd_kcontrol *snd_ac97_find_mixer_ctl(struct snd_ac97 *ac97, const char *name); static int snd_ac97_add_vmaster(struct snd_ac97 *ac97, char *name, - const unsigned int *tlv, const char **slaves); + const unsigned int *tlv, + const char * const *slaves); /* * Chip specific initialization @@ -3196,7 +3197,9 @@ static int cm9761_spdif_out_source_put(struct snd_kcontrol *kcontrol, struct snd ucontrol->value.enumerated.item[0] == 1 ? 0x2 : 0); } -static const char *cm9761_dac_clock[] = { "AC-Link", "SPDIF-In", "Both" }; +static const char * const cm9761_dac_clock[] = { + "AC-Link", "SPDIF-In", "Both" +}; static const struct ac97_enum cm9761_dac_clock_enum = AC97_ENUM_SINGLE(AC97_CM9761_SPDIF_CTRL, 9, 3, cm9761_dac_clock); @@ -3310,7 +3313,9 @@ static int patch_cm9761(struct snd_ac97 *ac97) #define AC97_CM9780_MULTI_CHAN 0x66 #define AC97_CM9780_SPDIF 0x6c -static const char *cm9780_ch_select[] = { "Front", "Side", "Center/LFE", "Rear" }; +static const char * const cm9780_ch_select[] = { + "Front", "Side", "Center/LFE", "Rear" +}; static const struct ac97_enum cm9780_ch_select_enum = AC97_ENUM_SINGLE(AC97_CM9780_MULTI_CHAN, 6, 4, cm9780_ch_select); static const struct snd_kcontrol_new cm9780_controls[] = { @@ -3356,7 +3361,7 @@ AC97_SINGLE("Downmix LFE and Center to Front", 0x5a, 12, 1, 0), AC97_SINGLE("Downmix Surround to Front", 0x5a, 11, 1, 0), }; -static const char *slave_vols_vt1616[] = { +static const char * const slave_vols_vt1616[] = { "Front Playback Volume", "Surround Playback Volume", "Center Playback Volume", @@ -3364,7 +3369,7 @@ static const char *slave_vols_vt1616[] = { NULL }; -static const char *slave_sws_vt1616[] = { +static const char * const slave_sws_vt1616[] = { "Front Playback Switch", "Surround Playback Switch", "Center Playback Switch", @@ -3385,10 +3390,11 @@ static struct snd_kcontrol *snd_ac97_find_mixer_ctl(struct snd_ac97 *ac97, /* create a virtual master control and add slaves */ static int snd_ac97_add_vmaster(struct snd_ac97 *ac97, char *name, - const unsigned int *tlv, const char **slaves) + const unsigned int *tlv, + const char * const *slaves) { struct snd_kcontrol *kctl; - const char **s; + const char * const *s; int err; kctl = snd_ctl_make_virtual_master(name, tlv); @@ -3612,7 +3618,7 @@ static int patch_vt1617a(struct snd_ac97 * ac97) struct vt1618_uaj_item { unsigned short mask; unsigned short shift; - const char *items[4]; + const char * const items[4]; }; /* This list reflects the vt1618 docs for Vendor Defined Register 0x60. */ diff --git a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h index 47bf8dfe8276..d1ce151fe722 100644 --- a/sound/pci/ac97/ac97_patch.h +++ b/sound/pci/ac97/ac97_patch.h @@ -49,7 +49,7 @@ struct ac97_enum { unsigned char shift_l; unsigned char shift_r; unsigned short mask; - const char **texts; + const char * const *texts; }; #define AC97_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts) \ -- cgit v1.2.3 From 30d0ae425ab1c9bb0003c3798de78fbf30ddebdc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:15:50 +0200 Subject: ALSA: asihpi: Use snd_ctl_enum_info() ... and reduce the open codes. Signed-off-by: Takashi Iwai --- sound/pci/asihpi/asihpi.c | 46 +++++----------------------------------------- 1 file changed, 5 insertions(+), 41 deletions(-) (limited to 'sound') diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index 5017176bfaa1..ac66b3228a34 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c @@ -1625,18 +1625,7 @@ static const char * const asihpi_aesebu_format_names[] = { static int snd_asihpi_aesebu_format_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - - strcpy(uinfo->value.enumerated.name, - asihpi_aesebu_format_names[uinfo->value.enumerated.item]); - - return 0; + return snd_ctl_enum_info(uinfo, 1, 3, asihpi_aesebu_format_names); } static int snd_asihpi_aesebu_format_get(struct snd_kcontrol *kcontrol, @@ -1863,22 +1852,7 @@ static int snd_asihpi_tuner_band_info(struct snd_kcontrol *kcontrol, if (num_bands < 0) return num_bands; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = num_bands; - - if (num_bands > 0) { - if (uinfo->value.enumerated.item >= - uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - - strcpy(uinfo->value.enumerated.name, - asihpi_tuner_band_names[ - tuner_bands[uinfo->value.enumerated.item]]); - - } - return 0; + return snd_ctl_enum_info(uinfo, 1, num_bands, asihpi_tuner_band_names); } static int snd_asihpi_tuner_band_get(struct snd_kcontrol *kcontrol, @@ -2253,7 +2227,7 @@ static int snd_asihpi_cmode_info(struct snd_kcontrol *kcontrol, u32 h_control = kcontrol->private_value; u16 mode; int i; - u16 mode_map[6]; + const char *mapped_names[6]; int valid_modes = 0; /* HPI channel mode values can be from 1 to 6 @@ -2262,24 +2236,14 @@ static int snd_asihpi_cmode_info(struct snd_kcontrol *kcontrol, for (i = 0; i < HPI_CHANNEL_MODE_LAST; i++) if (!hpi_channel_mode_query_mode( h_control, i, &mode)) { - mode_map[valid_modes] = mode; + mapped_names[valid_modes] = mode_names[mode]; valid_modes++; } if (!valid_modes) return -EINVAL; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = valid_modes; - - if (uinfo->value.enumerated.item >= valid_modes) - uinfo->value.enumerated.item = valid_modes - 1; - - strcpy(uinfo->value.enumerated.name, - mode_names[mode_map[uinfo->value.enumerated.item]]); - - return 0; + return snd_ctl_enum_info(uinfo, 1, valid_modes, mapped_names); } static int snd_asihpi_cmode_get(struct snd_kcontrol *kcontrol, -- cgit v1.2.3 From 4d765e48c5edb2090b82e97680b2d1ddf6d18c31 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:16:01 +0200 Subject: ALSA: aw2: Use snd_ctl_enum_info() ... and reduce the open codes. Also add missing const to the text array. Signed-off-by: Takashi Iwai --- sound/pci/aw2/aw2-alsa.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c index 3878cf5de9a4..e1cf01949fda 100644 --- a/sound/pci/aw2/aw2-alsa.c +++ b/sound/pci/aw2/aw2-alsa.c @@ -725,19 +725,10 @@ static int snd_aw2_new_pcm(struct aw2 *chip) static int snd_aw2_control_switch_capture_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[2] = { + static const char * const texts[2] = { "Analog", "Digital" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) { - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - } - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 2, texts); } static int snd_aw2_control_switch_capture_get(struct snd_kcontrol *kcontrol, -- cgit v1.2.3 From 9b311a0ad9ec0df9f010bcadd19193b1cee593f6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:16:13 +0200 Subject: ALSA: azt3328: Use snd_ctl_enum_info() ... and reduce the open codes. Signed-off-by: Takashi Iwai --- sound/pci/azt3328.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index 5a69e26cb2fb..fdbb9c05c77b 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -1034,11 +1034,6 @@ snd_azf3328_info_mixer_enum(struct snd_kcontrol *kcontrol, const char * const *p = NULL; snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = (reg.reg == IDX_MIXER_REC_SELECT) ? 2 : 1; - uinfo->value.enumerated.items = reg.enum_c; - if (uinfo->value.enumerated.item > reg.enum_c - 1U) - uinfo->value.enumerated.item = reg.enum_c - 1U; if (reg.reg == IDX_MIXER_ADVCTL2) { switch(reg.lchan_shift) { case 8: /* modem out sel */ @@ -1051,12 +1046,12 @@ snd_azf3328_info_mixer_enum(struct snd_kcontrol *kcontrol, p = texts4; break; } - } else - if (reg.reg == IDX_MIXER_REC_SELECT) + } else if (reg.reg == IDX_MIXER_REC_SELECT) p = texts3; - strcpy(uinfo->value.enumerated.name, p[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, + (reg.reg == IDX_MIXER_REC_SELECT) ? 2 : 1, + reg.enum_c, p); } static int -- cgit v1.2.3 From de95eae25a2744ba5f9bd3c862bb43a1b177ad58 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:16:26 +0200 Subject: ALSA: ca0106: Use snd_ctl_enum_info() ... and reduce the open codes. Also correct the array size and add missing const to text arrays. Signed-off-by: Takashi Iwai --- sound/pci/ca0106/ca0106_mixer.c | 40 ++++++++-------------------------------- 1 file changed, 8 insertions(+), 32 deletions(-) (limited to 'sound') diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 27de0de90018..68c0eb0a2807 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -185,17 +185,11 @@ static int snd_ca0106_shared_spdif_put(struct snd_kcontrol *kcontrol, static int snd_ca0106_capture_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[6] = { + static const char * const texts[6] = { "IEC958 out", "i2s mixer out", "IEC958 in", "i2s in", "AC97 in", "SRC out" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 6; - if (uinfo->value.enumerated.item > 5) - uinfo->value.enumerated.item = 5; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 6, texts); } static int snd_ca0106_capture_source_get(struct snd_kcontrol *kcontrol, @@ -228,17 +222,11 @@ static int snd_ca0106_capture_source_put(struct snd_kcontrol *kcontrol, static int snd_ca0106_i2c_capture_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[6] = { + static const char * const texts[4] = { "Phone", "Mic", "Line in", "Aux" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 4; - if (uinfo->value.enumerated.item > 3) - uinfo->value.enumerated.item = 3; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 4, texts); } static int snd_ca0106_i2c_capture_source_get(struct snd_kcontrol *kcontrol, @@ -273,29 +261,17 @@ static int snd_ca0106_i2c_capture_source_put(struct snd_kcontrol *kcontrol, static int snd_ca0106_capture_line_in_side_out_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[2] = { "Side out", "Line in" }; + static const char * const texts[2] = { "Side out", "Line in" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item > 1) - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 2, texts); } static int snd_ca0106_capture_mic_line_in_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[2] = { "Line in", "Mic in" }; + static const char * const texts[2] = { "Line in", "Mic in" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item > 1) - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 2, texts); } static int snd_ca0106_capture_mic_line_in_get(struct snd_kcontrol *kcontrol, -- cgit v1.2.3 From c69a4f3046ee5a28ab09a1786a73d04bd6177445 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:16:38 +0200 Subject: ALSA: echoaudio: Use snd_ctl_enum_info() ... and reduce the open codes. Also add missing const to text arrays. Signed-off-by: Takashi Iwai --- sound/pci/echoaudio/echoaudio.c | 33 ++++++--------------------------- 1 file changed, 6 insertions(+), 27 deletions(-) (limited to 'sound') diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 631aaa4046ad..d82321ff549b 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -1416,21 +1416,14 @@ static struct snd_kcontrol_new snd_echo_vmixer = { static int snd_echo_digital_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *names[4] = { + static const char * const names[4] = { "S/PDIF Coaxial", "S/PDIF Optical", "ADAT Optical", "S/PDIF Cdrom" }; struct echoaudio *chip; chip = snd_kcontrol_chip(kcontrol); - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->value.enumerated.items = chip->num_digital_modes; - uinfo->count = 1; - if (uinfo->value.enumerated.item >= chip->num_digital_modes) - uinfo->value.enumerated.item = chip->num_digital_modes - 1; - strcpy(uinfo->value.enumerated.name, names[ - chip->digital_mode_list[uinfo->value.enumerated.item]]); - return 0; + return snd_ctl_enum_info(uinfo, 1, chip->num_digital_modes, names); } static int snd_echo_digital_mode_get(struct snd_kcontrol *kcontrol, @@ -1509,16 +1502,9 @@ static struct snd_kcontrol_new snd_echo_digital_mode_switch = { static int snd_echo_spdif_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *names[2] = {"Consumer", "Professional"}; + static const char * const names[2] = {"Consumer", "Professional"}; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->value.enumerated.items = 2; - uinfo->count = 1; - if (uinfo->value.enumerated.item) - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, - names[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 2, names); } static int snd_echo_spdif_mode_get(struct snd_kcontrol *kcontrol, @@ -1566,21 +1552,14 @@ static struct snd_kcontrol_new snd_echo_spdif_mode_switch = { static int snd_echo_clock_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *names[8] = { + static const char * const names[8] = { "Internal", "Word", "Super", "S/PDIF", "ADAT", "ESync", "ESync96", "MTC" }; struct echoaudio *chip; chip = snd_kcontrol_chip(kcontrol); - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->value.enumerated.items = chip->num_clock_sources; - uinfo->count = 1; - if (uinfo->value.enumerated.item >= chip->num_clock_sources) - uinfo->value.enumerated.item = chip->num_clock_sources - 1; - strcpy(uinfo->value.enumerated.name, names[ - chip->clock_source_list[uinfo->value.enumerated.item]]); - return 0; + return snd_ctl_enum_info(uinfo, 1, chip->num_clock_sources, names); } static int snd_echo_clock_source_get(struct snd_kcontrol *kcontrol, -- cgit v1.2.3 From 1541c66d3bb78c8a388025b074c75658c790b72f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:16:48 +0200 Subject: ALSA: emu10k1: Use snd_ctl_enum_info() ... and reduce the open codes. Also add missing const to text arrays. Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emumixer.c | 58 ++++++++++---------------------------------- sound/pci/emu10k1/p16v.c | 20 +++------------ 2 files changed, 17 insertions(+), 61 deletions(-) (limited to 'sound') diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index c5ae2a24d8a5..1de33025669a 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -83,7 +83,7 @@ static int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol, * Items labels in enum mixer controls assigning source data to * each destination */ -static char *emu1010_src_texts[] = { +static const char * const emu1010_src_texts[] = { "Silence", "Dock Mic A", "Dock Mic B", @@ -141,7 +141,7 @@ static char *emu1010_src_texts[] = { /* 1616(m) cardbus */ -static char *emu1616_src_texts[] = { +static const char * const emu1616_src_texts[] = { "Silence", "Dock Mic A", "Dock Mic B", @@ -393,23 +393,11 @@ static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); - char **items; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) { - uinfo->value.enumerated.items = 49; - items = emu1616_src_texts; - } else { - uinfo->value.enumerated.items = 53; - items = emu1010_src_texts; - } - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - items[uinfo->value.enumerated.item]); - return 0; + if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) + return snd_ctl_enum_info(uinfo, 1, 49, emu1616_src_texts); + else + return snd_ctl_enum_info(uinfo, 1, 53, emu1010_src_texts); } static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol, @@ -699,19 +687,11 @@ static struct snd_kcontrol_new snd_emu1010_dac_pads[] = { static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[4] = { + static const char * const texts[4] = { "44100", "48000", "SPDIF", "ADAT" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 4; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; - - + return snd_ctl_enum_info(uinfo, 1, 4, texts); } static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol, @@ -830,21 +810,15 @@ static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { #if 0 - static char *texts[4] = { + static const char * const texts[4] = { "Unknown1", "Unknown2", "Mic", "Line" }; #endif - static char *texts[2] = { + static const char * const texts[2] = { "Mic", "Line" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item > 1) - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 2, texts); } static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol, @@ -997,15 +971,9 @@ static struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] = { #if 0 static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = {"44100", "48000", "96000"}; + static const char * const texts[] = {"44100", "48000", "96000"}; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 3, texts); } static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol, diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index a4fe7f0c9458..7ef3898a7806 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -757,18 +757,12 @@ static int snd_p16v_volume_put(struct snd_kcontrol *kcontrol, static int snd_p16v_capture_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[8] = { + static const char * const texts[8] = { "SPDIF", "I2S", "SRC48", "SRCMulti_SPDIF", "SRCMulti_I2S", "CDIF", "FX", "AC97" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 8; - if (uinfo->value.enumerated.item > 7) - uinfo->value.enumerated.item = 7; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 8, texts); } static int snd_p16v_capture_source_get(struct snd_kcontrol *kcontrol, @@ -805,15 +799,9 @@ static int snd_p16v_capture_source_put(struct snd_kcontrol *kcontrol, static int snd_p16v_capture_channel_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[4] = { "0", "1", "2", "3", }; + static const char * const texts[4] = { "0", "1", "2", "3", }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 4; - if (uinfo->value.enumerated.item > 3) - uinfo->value.enumerated.item = 3; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 4, texts); } static int snd_p16v_capture_channel_get(struct snd_kcontrol *kcontrol, -- cgit v1.2.3 From 6b6b295e8053dd5a005aaa089b5bed4b4a65c632 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:17:08 +0200 Subject: ALSA: es1938: Use snd_ctl_enum_info() ... and reduce the open codes. Also add missing const to the text array. Signed-off-by: Takashi Iwai --- sound/pci/es1938.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index 639962443ccc..0fc46eb4e251 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -1045,18 +1045,12 @@ static int snd_es1938_new_pcm(struct es1938 *chip, int device) static int snd_es1938_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[8] = { + static const char * const texts[8] = { "Mic", "Mic Master", "CD", "AOUT", "Mic1", "Mix", "Line", "Master" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 8; - if (uinfo->value.enumerated.item > 7) - uinfo->value.enumerated.item = 7; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 8, texts); } static int snd_es1938_get_mux(struct snd_kcontrol *kcontrol, -- cgit v1.2.3 From ca776a28ae10bb06807f23e807f0f459dab78318 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:17:17 +0200 Subject: ALSA: fm801: Use snd_ctl_enum_info() ... and reduce the open codes. Also add missing const to the text array. Signed-off-by: Takashi Iwai --- sound/pci/fm801.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index c5038303a126..d167afffce5f 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -958,17 +958,11 @@ static int snd_fm801_put_double(struct snd_kcontrol *kcontrol, static int snd_fm801_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[5] = { + static const char * const texts[5] = { "AC97 Primary", "FM", "I2S", "PCM", "AC97 Secondary" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 5; - if (uinfo->value.enumerated.item > 4) - uinfo->value.enumerated.item = 4; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 5, texts); } static int snd_fm801_get_mux(struct snd_kcontrol *kcontrol, -- cgit v1.2.3 From 3ff72219320f616489bf0d98ddac12899da4a9ce Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:17:28 +0200 Subject: ALSA: hda: Use snd_ctl_enum_info() ... and reduce the open codes. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 15e0089492f7..259fbeaa37bd 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2927,16 +2927,8 @@ static int vmaster_mute_mode_info(struct snd_kcontrol *kcontrol, static const char * const texts[] = { "On", "Off", "Follow Master" }; - unsigned int index; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - index = uinfo->value.enumerated.item; - if (index >= 3) - index = 2; - strcpy(uinfo->value.enumerated.name, texts[index]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 3, texts); } static int vmaster_mute_mode_get(struct snd_kcontrol *kcontrol, @@ -5195,14 +5187,7 @@ int snd_hda_enum_helper_info(struct snd_kcontrol *kcontrol, texts = texts_default; } - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = num_items; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, num_items, texts); } EXPORT_SYMBOL_GPL(snd_hda_enum_helper_info); -- cgit v1.2.3 From c4fa251f6f3ed00d59d0d8ee63bf346e6dd6b664 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:18:33 +0200 Subject: ALSA: ice1712: Use snd_ctl_enum_info() ... and reduce the open codes. Signed-off-by: Takashi Iwai --- sound/pci/ice1712/ews.c | 16 ++-------------- sound/pci/ice1712/ice1712.c | 27 ++++----------------------- 2 files changed, 6 insertions(+), 37 deletions(-) (limited to 'sound') diff --git a/sound/pci/ice1712/ews.c b/sound/pci/ice1712/ews.c index 817a1bc50a60..5cb587cf360e 100644 --- a/sound/pci/ice1712/ews.c +++ b/sound/pci/ice1712/ews.c @@ -580,13 +580,7 @@ static int snd_ice1712_ewx_io_sense_info(struct snd_kcontrol *kcontrol, struct s static const char * const texts[2] = { "+4dBu", "-10dBV", }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item >= 2) - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 2, texts); } static int snd_ice1712_ewx_io_sense_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -903,13 +897,7 @@ static int snd_ice1712_6fire_select_input_info(struct snd_kcontrol *kcontrol, st static const char * const texts[4] = { "Internal", "Front Input", "Rear Input", "Wave Table" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 4; - if (uinfo->value.enumerated.item >= 4) - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 4, texts); } static int snd_ice1712_6fire_select_input_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index 206ed2cbcef9..48a0c330da24 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -1839,13 +1839,7 @@ static int snd_ice1712_pro_internal_clock_info(struct snd_kcontrol *kcontrol, "96000", /* 12: 7 */ "IEC958 Input", /* 13: -- */ }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 14; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 14, texts); } static int snd_ice1712_pro_internal_clock_get(struct snd_kcontrol *kcontrol, @@ -1930,13 +1924,7 @@ static int snd_ice1712_pro_internal_clock_default_info(struct snd_kcontrol *kcon "96000", /* 12: 7 */ /* "IEC958 Input", 13: -- */ }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 13; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 13, texts); } static int snd_ice1712_pro_internal_clock_default_get(struct snd_kcontrol *kcontrol, @@ -2057,15 +2045,8 @@ static int snd_ice1712_pro_route_info(struct snd_kcontrol *kcontrol, "IEC958 In L", "IEC958 In R", /* 9-10 */ "Digital Mixer", /* 11 - optional */ }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = - snd_ctl_get_ioffidx(kcontrol, &uinfo->id) < 2 ? 12 : 11; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + int num_items = snd_ctl_get_ioffidx(kcontrol, &uinfo->id) < 2 ? 12 : 11; + return snd_ctl_enum_info(uinfo, 1, num_items, texts); } static int snd_ice1712_pro_route_analog_get(struct snd_kcontrol *kcontrol, -- cgit v1.2.3 From 597da2e4dfa04c8ee66b09fce931ab6825bc3e75 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:18:50 +0200 Subject: ALSA: ice1724: Use snd_ctl_enum_info() ... and reduce the open codes. Also add missing const to text arrays. Signed-off-by: Takashi Iwai --- sound/pci/ice1712/aureon.c | 46 +++++++--------------------------------- sound/pci/ice1712/ice1724.c | 8 +------ sound/pci/ice1712/maya44.c | 20 ++--------------- sound/pci/ice1712/phase.c | 12 +---------- sound/pci/ice1712/pontis.c | 8 +------ sound/pci/ice1712/prodigy192.c | 18 ++-------------- sound/pci/ice1712/prodigy_hifi.c | 11 ++-------- sound/pci/ice1712/quartet.c | 27 ++++------------------- sound/pci/ice1712/se.c | 9 +------- 9 files changed, 22 insertions(+), 137 deletions(-) (limited to 'sound') diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c index 3b3cf4ac9060..c9411dfff5a4 100644 --- a/sound/pci/ice1712/aureon.c +++ b/sound/pci/ice1712/aureon.c @@ -205,13 +205,7 @@ static int aureon_universe_inmux_info(struct snd_kcontrol *kcontrol, static const char * const texts[3] = {"Internal Aux", "Wavetable", "Rear Line-In"}; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 3, texts); } static int aureon_universe_inmux_get(struct snd_kcontrol *kcontrol, @@ -1106,20 +1100,10 @@ static int wm_adc_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_in }; struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 2; - if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON71_UNIVERSE) { - uinfo->value.enumerated.items = 8; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, universe_texts[uinfo->value.enumerated.item]); - } else { - uinfo->value.enumerated.items = 5; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - } - return 0; + if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON71_UNIVERSE) + return snd_ctl_enum_info(uinfo, 2, 8, universe_texts); + else + return snd_ctl_enum_info(uinfo, 2, 5, texts); } static int wm_adc_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1167,16 +1151,10 @@ static int aureon_cs8415_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_ "CD", "Coax" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71) - strcpy(uinfo->value.enumerated.name, prodigy_texts[uinfo->value.enumerated.item]); + return snd_ctl_enum_info(uinfo, 1, 2, prodigy_texts); else - strcpy(uinfo->value.enumerated.name, aureon_texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 2, aureon_texts); } static int aureon_cs8415_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1392,15 +1370,7 @@ static int aureon_oversampling_info(struct snd_kcontrol *k, struct snd_ctl_elem_ { static const char * const texts[2] = { "128x", "64x" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - - return 0; + return snd_ctl_enum_info(uinfo, 1, 2, texts); } static int aureon_oversampling_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 08cb08ac85e6..f633e3bb4c43 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -2049,13 +2049,7 @@ static int snd_vt1724_pro_route_info(struct snd_kcontrol *kcontrol, "IEC958 In L", "IEC958 In R", /* 3-4 */ }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 5; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 5, texts); } static inline int analog_route_shift(int idx) diff --git a/sound/pci/ice1712/maya44.c b/sound/pci/ice1712/maya44.c index 63aa39f06f02..7de25c4807fd 100644 --- a/sound/pci/ice1712/maya44.c +++ b/sound/pci/ice1712/maya44.c @@ -359,15 +359,7 @@ static int maya_rec_src_info(struct snd_kcontrol *kcontrol, { static const char * const texts[] = { "Line", "Mic" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = ARRAY_SIZE(texts); - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); } static int maya_rec_src_get(struct snd_kcontrol *kcontrol, @@ -411,15 +403,7 @@ static int maya_pb_route_info(struct snd_kcontrol *kcontrol, "Input 1", "Input 2", "Input 3", "Input 4" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = ARRAY_SIZE(texts); - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); } static int maya_pb_route_shift(int idx) diff --git a/sound/pci/ice1712/phase.c b/sound/pci/ice1712/phase.c index 0011e04f36a2..e9ca89c9174b 100644 --- a/sound/pci/ice1712/phase.c +++ b/sound/pci/ice1712/phase.c @@ -723,17 +723,7 @@ static int phase28_oversampling_info(struct snd_kcontrol *k, { static const char * const texts[2] = { "128x", "64x" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - - return 0; + return snd_ctl_enum_info(uinfo, 1, 2, texts); } static int phase28_oversampling_get(struct snd_kcontrol *kcontrol, diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c index 5555eb4b2400..5101f40f6fbd 100644 --- a/sound/pci/ice1712/pontis.c +++ b/sound/pci/ice1712/pontis.c @@ -417,13 +417,7 @@ static int cs_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_inf "Optical", /* RXP1 */ "CD", /* RXP2 */ }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 3, texts); } static int cs_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c index f3b491aa3e22..1eb151aaa965 100644 --- a/sound/pci/ice1712/prodigy192.c +++ b/sound/pci/ice1712/prodigy192.c @@ -284,15 +284,7 @@ static int stac9460_mic_sw_info(struct snd_kcontrol *kcontrol, { static const char * const texts[2] = { "Line In", "Mic" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - - return 0; + return snd_ctl_enum_info(uinfo, 1, 2, texts); } @@ -563,13 +555,7 @@ static int ak4114_input_sw_info(struct snd_kcontrol *kcontrol, { static const char * const texts[2] = { "Toslink", "Coax" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 2, texts); } diff --git a/sound/pci/ice1712/prodigy_hifi.c b/sound/pci/ice1712/prodigy_hifi.c index 2261d1e49150..2697402b5195 100644 --- a/sound/pci/ice1712/prodigy_hifi.c +++ b/sound/pci/ice1712/prodigy_hifi.c @@ -537,7 +537,7 @@ static int wm_master_vol_put(struct snd_kcontrol *kcontrol, static int wm_adc_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char* texts[32] = { + static const char * const texts[32] = { "NULL", WM_AIN1, WM_AIN2, WM_AIN1 "+" WM_AIN2, WM_AIN3, WM_AIN1 "+" WM_AIN3, WM_AIN2 "+" WM_AIN3, WM_AIN1 "+" WM_AIN2 "+" WM_AIN3, @@ -560,14 +560,7 @@ static int wm_adc_mux_enum_info(struct snd_kcontrol *kcontrol, WM_AIN1 "+" WM_AIN2 "+" WM_AIN3 "+" WM_AIN4 "+" WM_AIN5 }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 32; - if (uinfo->value.enumerated.item > 31) - uinfo->value.enumerated.item = 31; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 32, texts); } static int wm_adc_mux_enum_get(struct snd_kcontrol *kcontrol, diff --git a/sound/pci/ice1712/quartet.c b/sound/pci/ice1712/quartet.c index 2c2df4b74e01..d4caf9d05922 100644 --- a/sound/pci/ice1712/quartet.c +++ b/sound/pci/ice1712/quartet.c @@ -46,7 +46,7 @@ struct qtet_kcontrol_private { unsigned int bit; void (*set_register)(struct snd_ice1712 *ice, unsigned int val); unsigned int (*get_register)(struct snd_ice1712 *ice); - unsigned char * const texts[2]; + const char * const texts[2]; }; enum { @@ -554,17 +554,7 @@ static int qtet_ain12_enum_info(struct snd_kcontrol *kcontrol, { static const char * const texts[3] = {"Line In 1/2", "Mic", "Mic + Low-cut"}; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = ARRAY_SIZE(texts); - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - - return 0; + return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); } static int qtet_ain12_sw_get(struct snd_kcontrol *kcontrol, @@ -706,17 +696,8 @@ static int qtet_enum_info(struct snd_kcontrol *kcontrol, { struct qtet_kcontrol_private private = qtet_privates[kcontrol->private_value]; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = ARRAY_SIZE(private.texts); - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - private.texts[uinfo->value.enumerated.item]); - - return 0; + return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(private.texts), + private.texts); } static int qtet_sw_get(struct snd_kcontrol *kcontrol, diff --git a/sound/pci/ice1712/se.c b/sound/pci/ice1712/se.c index ffd894bb4507..1c5d5b22c7a0 100644 --- a/sound/pci/ice1712/se.c +++ b/sound/pci/ice1712/se.c @@ -452,14 +452,7 @@ static int se200pci_cont_enum_info(struct snd_kcontrol *kc, c = se200pci_get_enum_count(n); if (!c) return -EINVAL; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = c; - if (uinfo->value.enumerated.item >= c) - uinfo->value.enumerated.item = c - 1; - strcpy(uinfo->value.enumerated.name, - se200pci_cont[n].member[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, c, se200pci_cont[n].member); } static int se200pci_cont_volume_get(struct snd_kcontrol *kc, -- cgit v1.2.3 From f861237c80a07449abd351c04a6ba397418dc0ee Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:21:58 +0200 Subject: ALSA: korg1212: Use snd_ctl_enum_info() ... and reduce the open codes. Also add missing const to text arrays. Signed-off-by: Takashi Iwai --- sound/pci/korg1212/korg1212.c | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) (limited to 'sound') diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index 9fe549b2efdf..59d21c9401d2 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -444,9 +444,9 @@ static char *stateName[] = { "Invalid" }; -static char *clockSourceTypeName[] = { "ADAT", "S/PDIF", "local" }; +static const char * const clockSourceTypeName[] = { "ADAT", "S/PDIF", "local" }; -static char *clockSourceName[] = { +static const char * const clockSourceName[] = { "ADAT at 44.1 kHz", "ADAT at 48 kHz", "S/PDIF at 44.1 kHz", @@ -455,7 +455,7 @@ static char *clockSourceName[] = { "local clock at 48 kHz" }; -static char *channelName[] = { +static const char * const channelName[] = { "ADAT-1", "ADAT-2", "ADAT-3", @@ -1844,14 +1844,9 @@ static int snd_korg1212_control_volume_put(struct snd_kcontrol *kcontrol, static int snd_korg1212_control_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = (kcontrol->private_value >= 8) ? 2 : 1; - uinfo->value.enumerated.items = kAudioChannels; - if (uinfo->value.enumerated.item > kAudioChannels-1) { - uinfo->value.enumerated.item = kAudioChannels-1; - } - strcpy(uinfo->value.enumerated.name, channelName[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, + (kcontrol->private_value >= 8) ? 2 : 1, + kAudioChannels, channelName); } static int snd_korg1212_control_route_get(struct snd_kcontrol *kcontrol, @@ -1961,14 +1956,7 @@ static int snd_korg1212_control_put(struct snd_kcontrol *kcontrol, static int snd_korg1212_control_sync_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - if (uinfo->value.enumerated.item > 2) { - uinfo->value.enumerated.item = 2; - } - strcpy(uinfo->value.enumerated.name, clockSourceTypeName[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 3, clockSourceTypeName); } static int snd_korg1212_control_sync_get(struct snd_kcontrol *kcontrol, -- cgit v1.2.3 From 08455ace3cafd9b0b5c35db3d89c4388f6d3a6fe Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:19:00 +0200 Subject: ALSA: pcxhr: Use snd_ctl_enum_info() ... and reduce the open codes. Signed-off-by: Takashi Iwai --- sound/pci/pcxhr/pcxhr_mixer.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/pci/pcxhr/pcxhr_mixer.c b/sound/pci/pcxhr/pcxhr_mixer.c index 95c9571780d8..63136c4f3f3d 100644 --- a/sound/pci/pcxhr/pcxhr_mixer.c +++ b/sound/pci/pcxhr/pcxhr_mixer.c @@ -660,14 +660,7 @@ static int pcxhr_audio_src_info(struct snd_kcontrol *kcontrol, if (chip->mgr->board_has_mic) i = 5; /* Mic and MicroMix available */ } - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = i; - if (uinfo->value.enumerated.item > (i-1)) - uinfo->value.enumerated.item = i-1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, i, texts); } static int pcxhr_audio_src_get(struct snd_kcontrol *kcontrol, @@ -756,14 +749,7 @@ static int pcxhr_clock_type_info(struct snd_kcontrol *kcontrol, texts = textsPCXHR; snd_BUG_ON(clock_items > (PCXHR_CLOCK_TYPE_MAX+1)); } - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = clock_items; - if (uinfo->value.enumerated.item >= clock_items) - uinfo->value.enumerated.item = clock_items-1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, clock_items, texts); } static int pcxhr_clock_type_get(struct snd_kcontrol *kcontrol, -- cgit v1.2.3 From 11c6ef7c8d439ef2bc3c95e5a4dcea449ab1f90f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:19:12 +0200 Subject: ALSA: rme32: Use snd_ctl_enum_info() ... and reduce the open codes. Also add missing const to text arrays. Signed-off-by: Takashi Iwai --- sound/pci/rme32.c | 34 ++++++++++------------------------ 1 file changed, 10 insertions(+), 24 deletions(-) (limited to 'sound') diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index 4afd3cab775b..6c60dcd2e5a1 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -1608,30 +1608,24 @@ snd_rme32_info_inputtype_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { struct rme32 *rme32 = snd_kcontrol_chip(kcontrol); - static char *texts[4] = { "Optical", "Coaxial", "Internal", "XLR" }; + static const char * const texts[4] = { + "Optical", "Coaxial", "Internal", "XLR" + }; + int num_items; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; switch (rme32->pci->device) { case PCI_DEVICE_ID_RME_DIGI32: case PCI_DEVICE_ID_RME_DIGI32_8: - uinfo->value.enumerated.items = 3; + num_items = 3; break; case PCI_DEVICE_ID_RME_DIGI32_PRO: - uinfo->value.enumerated.items = 4; + num_items = 4; break; default: snd_BUG(); - break; - } - if (uinfo->value.enumerated.item > - uinfo->value.enumerated.items - 1) { - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; + return -EINVAL; } - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, num_items, texts); } static int snd_rme32_get_inputtype_control(struct snd_kcontrol *kcontrol, @@ -1695,20 +1689,12 @@ static int snd_rme32_info_clockmode_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[4] = { "AutoSync", + static const char * const texts[4] = { "AutoSync", "Internal 32.0kHz", "Internal 44.1kHz", "Internal 48.0kHz" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 4; - if (uinfo->value.enumerated.item > 3) { - uinfo->value.enumerated.item = 3; - } - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 4, texts); } static int snd_rme32_get_clockmode_control(struct snd_kcontrol *kcontrol, -- cgit v1.2.3 From 9c30d46a0fb3b294faf1226025071d6e802a8c36 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:19:23 +0200 Subject: ALSA: rme96: Use snd_ctl_enum_info() ... and reduce the open codes. Also add missing const to text arrays. Signed-off-by: Takashi Iwai --- sound/pci/rme96.c | 62 +++++++++++++++++++------------------------------------ 1 file changed, 21 insertions(+), 41 deletions(-) (limited to 'sound') diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index 5a395c87c6fc..2f1a85185a16 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -1884,39 +1884,38 @@ snd_rme96_put_loopback_control(struct snd_kcontrol *kcontrol, struct snd_ctl_ele static int snd_rme96_info_inputtype_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *_texts[5] = { "Optical", "Coaxial", "Internal", "XLR", "Analog" }; + static const char * const _texts[5] = { + "Optical", "Coaxial", "Internal", "XLR", "Analog" + }; struct rme96 *rme96 = snd_kcontrol_chip(kcontrol); - char *texts[5] = { _texts[0], _texts[1], _texts[2], _texts[3], _texts[4] }; + const char *texts[5] = { + _texts[0], _texts[1], _texts[2], _texts[3], _texts[4] + }; + int num_items; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; switch (rme96->pci->device) { case PCI_DEVICE_ID_RME_DIGI96: case PCI_DEVICE_ID_RME_DIGI96_8: - uinfo->value.enumerated.items = 3; + num_items = 3; break; case PCI_DEVICE_ID_RME_DIGI96_8_PRO: - uinfo->value.enumerated.items = 4; + num_items = 4; break; case PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST: if (rme96->rev > 4) { /* PST */ - uinfo->value.enumerated.items = 4; + num_items = 4; texts[3] = _texts[4]; /* Analog instead of XLR */ } else { /* PAD */ - uinfo->value.enumerated.items = 5; + num_items = 5; } break; default: snd_BUG(); - break; - } - if (uinfo->value.enumerated.item > uinfo->value.enumerated.items - 1) { - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + return -EINVAL; } - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, num_items, texts); } static int snd_rme96_get_inputtype_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -2002,16 +2001,9 @@ snd_rme96_put_inputtype_control(struct snd_kcontrol *kcontrol, struct snd_ctl_el static int snd_rme96_info_clockmode_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[3] = { "AutoSync", "Internal", "Word" }; + static const char * const texts[3] = { "AutoSync", "Internal", "Word" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - if (uinfo->value.enumerated.item > 2) { - uinfo->value.enumerated.item = 2; - } - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 3, texts); } static int snd_rme96_get_clockmode_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -2041,16 +2033,11 @@ snd_rme96_put_clockmode_control(struct snd_kcontrol *kcontrol, struct snd_ctl_el static int snd_rme96_info_attenuation_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[4] = { "0 dB", "-6 dB", "-12 dB", "-18 dB" }; + static const char * const texts[4] = { + "0 dB", "-6 dB", "-12 dB", "-18 dB" + }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 4; - if (uinfo->value.enumerated.item > 3) { - uinfo->value.enumerated.item = 3; - } - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 4, texts); } static int snd_rme96_get_attenuation_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -2081,16 +2068,9 @@ snd_rme96_put_attenuation_control(struct snd_kcontrol *kcontrol, struct snd_ctl_ static int snd_rme96_info_montracks_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[4] = { "1+2", "3+4", "5+6", "7+8" }; + static const char * const texts[4] = { "1+2", "3+4", "5+6", "7+8" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 4; - if (uinfo->value.enumerated.item > 3) { - uinfo->value.enumerated.item = 3; - } - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 4, texts); } static int snd_rme96_get_montracks_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -- cgit v1.2.3 From 8d678da9f0afbb951778369510c09b99de608c24 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:19:34 +0200 Subject: ALSA: hdsp: Use snd_ctl_enum_info() ... and reduce the open codes. Also add missing const to text arrays. Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdsp.c | 175 +++++++++++++++-------------------------------- 1 file changed, 57 insertions(+), 118 deletions(-) (limited to 'sound') diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 7646ba1664eb..2eb8baf7b828 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -1680,16 +1680,13 @@ static int hdsp_set_spdif_input(struct hdsp *hdsp, int in) static int snd_hdsp_info_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[4] = {"Optical", "Coaxial", "Internal", "AES"}; + static const char * const texts[4] = { + "Optical", "Coaxial", "Internal", "AES" + }; struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = ((hdsp->io_type == H9632) ? 4 : 3); - if (uinfo->value.enumerated.item > ((hdsp->io_type == H9632) ? 3 : 2)) - uinfo->value.enumerated.item = ((hdsp->io_type == H9632) ? 3 : 2); - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, (hdsp->io_type == H9632) ? 4 : 3, + texts); } static int snd_hdsp_get_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1786,16 +1783,14 @@ static int snd_hdsp_put_toggle_setting(struct snd_kcontrol *kcontrol, static int snd_hdsp_info_spdif_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = {"32000", "44100", "48000", "64000", "88200", "96000", "None", "128000", "176400", "192000"}; + static const char * const texts[] = { + "32000", "44100", "48000", "64000", "88200", "96000", + "None", "128000", "176400", "192000" + }; struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = (hdsp->io_type == H9632) ? 10 : 7; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, (hdsp->io_type == H9632) ? 10 : 7, + texts); } static int snd_hdsp_get_spdif_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1872,14 +1867,13 @@ static int snd_hdsp_get_system_sample_rate(struct snd_kcontrol *kcontrol, struct static int snd_hdsp_info_autosync_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); - static char *texts[] = {"32000", "44100", "48000", "64000", "88200", "96000", "None", "128000", "176400", "192000"}; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = (hdsp->io_type == H9632) ? 10 : 7 ; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + static const char * const texts[] = { + "32000", "44100", "48000", "64000", "88200", "96000", + "None", "128000", "176400", "192000" + }; + + return snd_ctl_enum_info(uinfo, 1, (hdsp->io_type == H9632) ? 10 : 7, + texts); } static int snd_hdsp_get_autosync_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1940,15 +1934,9 @@ static int hdsp_system_clock_mode(struct hdsp *hdsp) static int snd_hdsp_info_system_clock_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = {"Master", "Slave" }; + static const char * const texts[] = {"Master", "Slave" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 2, texts); } static int snd_hdsp_get_system_clock_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -2049,19 +2037,16 @@ static int hdsp_set_clock_source(struct hdsp *hdsp, int mode) static int snd_hdsp_info_clock_source(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = {"AutoSync", "Internal 32.0 kHz", "Internal 44.1 kHz", "Internal 48.0 kHz", "Internal 64.0 kHz", "Internal 88.2 kHz", "Internal 96.0 kHz", "Internal 128 kHz", "Internal 176.4 kHz", "Internal 192.0 KHz" }; + static const char * const texts[] = { + "AutoSync", "Internal 32.0 kHz", "Internal 44.1 kHz", + "Internal 48.0 kHz", "Internal 64.0 kHz", "Internal 88.2 kHz", + "Internal 96.0 kHz", "Internal 128 kHz", "Internal 176.4 kHz", + "Internal 192.0 KHz" + }; struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - if (hdsp->io_type == H9632) - uinfo->value.enumerated.items = 10; - else - uinfo->value.enumerated.items = 7; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, (hdsp->io_type == H9632) ? 10 : 7, + texts); } static int snd_hdsp_get_clock_source(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -2165,15 +2150,9 @@ static int hdsp_set_da_gain(struct hdsp *hdsp, int mode) static int snd_hdsp_info_da_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = {"Hi Gain", "+4 dBu", "-10 dbV"}; + static const char * const texts[] = {"Hi Gain", "+4 dBu", "-10 dbV"}; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 3, texts); } static int snd_hdsp_get_da_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -2250,15 +2229,9 @@ static int hdsp_set_ad_gain(struct hdsp *hdsp, int mode) static int snd_hdsp_info_ad_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = {"-10 dBV", "+4 dBu", "Lo Gain"}; + static const char * const texts[] = {"-10 dBV", "+4 dBu", "Lo Gain"}; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 3, texts); } static int snd_hdsp_get_ad_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -2335,15 +2308,9 @@ static int hdsp_set_phone_gain(struct hdsp *hdsp, int mode) static int snd_hdsp_info_phone_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = {"0 dB", "-6 dB", "-12 dB"}; + static const char * const texts[] = {"0 dB", "-6 dB", "-12 dB"}; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 3, texts); } static int snd_hdsp_get_phone_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -2439,31 +2406,28 @@ static int hdsp_set_pref_sync_ref(struct hdsp *hdsp, int pref) static int snd_hdsp_info_pref_sync_ref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = {"Word", "IEC958", "ADAT1", "ADAT Sync", "ADAT2", "ADAT3" }; + static const char * const texts[] = { + "Word", "IEC958", "ADAT1", "ADAT Sync", "ADAT2", "ADAT3" + }; struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; + int num_items; switch (hdsp->io_type) { case Digiface: case H9652: - uinfo->value.enumerated.items = 6; + num_items = 6; break; case Multiface: - uinfo->value.enumerated.items = 4; + num_items = 4; break; case H9632: - uinfo->value.enumerated.items = 3; + num_items = 3; break; default: return -EINVAL; } - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, num_items, texts); } static int snd_hdsp_get_pref_sync_ref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -2543,15 +2507,11 @@ static int hdsp_autosync_ref(struct hdsp *hdsp) static int snd_hdsp_info_autosync_ref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = {"Word", "ADAT Sync", "IEC958", "None", "ADAT1", "ADAT2", "ADAT3" }; + static const char * const texts[] = { + "Word", "ADAT Sync", "IEC958", "None", "ADAT1", "ADAT2", "ADAT3" + }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 7; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 7, texts); } static int snd_hdsp_get_autosync_ref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -2738,14 +2698,9 @@ static int snd_hdsp_put_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem static int snd_hdsp_info_sync_check(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = {"No Lock", "Lock", "Sync" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + static const char * const texts[] = {"No Lock", "Lock", "Sync" }; + + return snd_ctl_enum_info(uinfo, 1, 3, texts); } static int hdsp_wc_sync_check(struct hdsp *hdsp) @@ -3101,15 +3056,11 @@ static int snd_hdsp_put_rpm_input12(struct snd_kcontrol *kcontrol, struct snd_ct static int snd_hdsp_info_rpm_input(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = {"Phono +6dB", "Phono 0dB", "Phono -6dB", "Line 0dB", "Line -6dB"}; + static const char * const texts[] = { + "Phono +6dB", "Phono 0dB", "Phono -6dB", "Line 0dB", "Line -6dB" + }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 5; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 5, texts); } @@ -3234,15 +3185,9 @@ static int snd_hdsp_put_rpm_bypass(struct snd_kcontrol *kcontrol, struct snd_ctl static int snd_hdsp_info_rpm_bypass(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = {"On", "Off"}; + static const char * const texts[] = {"On", "Off"}; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 2, texts); } @@ -3291,15 +3236,9 @@ static int snd_hdsp_put_rpm_disconnect(struct snd_kcontrol *kcontrol, struct snd static int snd_hdsp_info_rpm_disconnect(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = {"On", "Off"}; + static const char * const texts[] = {"On", "Off"}; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 2, texts); } static struct snd_kcontrol_new snd_hdsp_rpm_controls[] = { -- cgit v1.2.3 From c69a637b4df37fc5a011a89e422636ea393af5b0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:19:41 +0200 Subject: ALSA: hdspm: Use snd_ctl_enum_info() ... and reduce the open codes. Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 52d86af3ef2d..7f7277bfb66a 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -2645,18 +2645,7 @@ static int hdspm_set_clock_source(struct hdspm * hdspm, int mode) static int snd_hdspm_info_clock_source(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 9; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - - strcpy(uinfo->value.enumerated.name, - texts_freq[uinfo->value.enumerated.item+1]); - - return 0; + return snd_ctl_enum_info(uinfo, 1, 9, texts_freq + 1); } static int snd_hdspm_get_clock_source(struct snd_kcontrol *kcontrol, -- cgit v1.2.3 From 7298ece7a26753b073a9ce5f979a4942d3904d44 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:19:53 +0200 Subject: ALSA: rme9652: Use snd_ctl_enum_info() ... and reduce the open codes. Also add missing const to text arrays. Signed-off-by: Takashi Iwai --- sound/pci/rme9652/rme9652.c | 58 ++++++++++++++------------------------------- 1 file changed, 18 insertions(+), 40 deletions(-) (limited to 'sound') diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index fa9a2a8dce5a..6521521853b8 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -920,15 +920,9 @@ static int rme9652_set_adat1_input(struct snd_rme9652 *rme9652, int internal) static int snd_rme9652_info_adat1_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[2] = {"ADAT1", "Internal"}; + static const char * const texts[2] = {"ADAT1", "Internal"}; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item > 1) - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 2, texts); } static int snd_rme9652_get_adat1_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -991,15 +985,9 @@ static int rme9652_set_spdif_input(struct snd_rme9652 *rme9652, int in) static int snd_rme9652_info_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[3] = {"ADAT1", "Coaxial", "Internal"}; + static const char * const texts[3] = {"ADAT1", "Coaxial", "Internal"}; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - if (uinfo->value.enumerated.item > 2) - uinfo->value.enumerated.item = 2; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 3, texts); } static int snd_rme9652_get_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1140,15 +1128,11 @@ static int rme9652_set_sync_mode(struct snd_rme9652 *rme9652, int mode) static int snd_rme9652_info_sync_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[3] = {"AutoSync", "Master", "Word Clock"}; + static const char * const texts[3] = { + "AutoSync", "Master", "Word Clock" + }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - if (uinfo->value.enumerated.item > 2) - uinfo->value.enumerated.item = 2; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 3, texts); } static int snd_rme9652_get_sync_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1231,16 +1215,14 @@ static int rme9652_set_sync_pref(struct snd_rme9652 *rme9652, int pref) static int snd_rme9652_info_sync_pref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[4] = {"IEC958 In", "ADAT1 In", "ADAT2 In", "ADAT3 In"}; + static const char * const texts[4] = { + "IEC958 In", "ADAT1 In", "ADAT2 In", "ADAT3 In" + }; struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol); - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = rme9652->ss_channels == RME9652_NCHANNELS ? 4 : 3; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, + rme9652->ss_channels == RME9652_NCHANNELS ? 4 : 3, + texts); } static int snd_rme9652_get_sync_pref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1392,15 +1374,11 @@ static int snd_rme9652_get_spdif_rate(struct snd_kcontrol *kcontrol, struct snd_ static int snd_rme9652_info_adat_sync(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[4] = {"No Lock", "Lock", "No Lock Sync", "Lock Sync"}; + static const char * const texts[4] = { + "No Lock", "Lock", "No Lock Sync", "Lock Sync" + }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 4; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 4, texts); } static int snd_rme9652_get_adat_sync(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -- cgit v1.2.3 From 3e4bc5b78e5516585941c7888287ed50a5090bf4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:20:07 +0200 Subject: ALSA: sonicvibes: Use snd_ctl_enum_info() ... and reduce the open codes. Also add missing const to the text array. Signed-off-by: Takashi Iwai --- sound/pci/sonicvibes.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c index 5b0d317cc9a6..313a7328bf9c 100644 --- a/sound/pci/sonicvibes.c +++ b/sound/pci/sonicvibes.c @@ -918,17 +918,11 @@ static int snd_sonicvibes_pcm(struct sonicvibes *sonic, int device, static int snd_sonicvibes_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[7] = { + static const char * const texts[7] = { "CD", "PCM", "Aux1", "Line", "Aux0", "Mic", "Mix" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 2; - uinfo->value.enumerated.items = 7; - if (uinfo->value.enumerated.item >= 7) - uinfo->value.enumerated.item = 6; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 2, 7, texts); } static int snd_sonicvibes_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -- cgit v1.2.3 From 9883ab91e3ba5229bfe2d6e7f6ff497a2d03d4d2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:20:18 +0200 Subject: ALSA: via82xx: Use snd_ctl_enum_info() ... and reduce the open codes. Also add missing const to the text array. Signed-off-by: Takashi Iwai --- sound/pci/via82xx.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index ecedf4dbfa2a..e088467fb736 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -1610,16 +1610,10 @@ static int snd_via8233_capture_source_info(struct snd_kcontrol *kcontrol, /* formerly they were "Line" and "Mic", but it looks like that they * have nothing to do with the actual physical connections... */ - static char *texts[2] = { + static const char * const texts[2] = { "Input1", "Input2" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item >= 2) - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 2, texts); } static int snd_via8233_capture_source_get(struct snd_kcontrol *kcontrol, -- cgit v1.2.3 From 9502272163ace71d77d809937216fd669c02364b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:20:28 +0200 Subject: ALSA: ppc: Use snd_ctl_enum_info() ... and reduce the open codes. Also add missing const to the text array. Signed-off-by: Takashi Iwai --- sound/ppc/tumbler.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index b9ffc17a4799..24c8766a925d 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c @@ -795,16 +795,11 @@ static int snapper_set_capture_source(struct pmac_tumbler *mix) static int snapper_info_capture_source(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[2] = { + static const char * const texts[2] = { "Line", "Mic" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item > 1) - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + + return snd_ctl_enum_info(uinfo, 1, 2, texts); } static int snapper_get_capture_source(struct snd_kcontrol *kcontrol, -- cgit v1.2.3 From 5fe0b0e3ea1c8cb704677ef7e85345bb683f9182 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:21:15 +0200 Subject: ALSA: sparc: Use snd_ctl_enum_info() ... and reduce the open codes. Also add missing const to the text array. Signed-off-by: Takashi Iwai --- sound/sparc/cs4231.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c index 4e91bcaa3664..06606f9bbf78 100644 --- a/sound/sparc/cs4231.c +++ b/sound/sparc/cs4231.c @@ -1285,19 +1285,11 @@ static int snd_cs4231_timer(struct snd_card *card) static int snd_cs4231_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[4] = { + static const char * const texts[4] = { "Line", "CD", "Mic", "Mix" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 2; - uinfo->value.enumerated.items = 4; - if (uinfo->value.enumerated.item > 3) - uinfo->value.enumerated.item = 3; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - - return 0; + return snd_ctl_enum_info(uinfo, 2, 4, texts); } static int snd_cs4231_get_mux(struct snd_kcontrol *kcontrol, -- cgit v1.2.3 From c8dd33fc80cd344d28a1f6a7e1f0af1cf7a2ffd1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:21:27 +0200 Subject: ALSA: 6fire: Use snd_ctl_enum_info() ... and reduce the open codes. Also add missing const to text arrays. Signed-off-by: Takashi Iwai --- sound/usb/6fire/control.c | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/usb/6fire/control.c b/sound/usb/6fire/control.c index 184e3987ac24..54656eed6e2e 100644 --- a/sound/usb/6fire/control.c +++ b/sound/usb/6fire/control.c @@ -25,8 +25,8 @@ #include "comm.h" #include "chip.h" -static char *opt_coax_texts[2] = { "Optical", "Coax" }; -static char *line_phono_texts[2] = { "Line", "Phono" }; +static const char * const opt_coax_texts[2] = { "Optical", "Coax" }; +static const char * const line_phono_texts[2] = { "Line", "Phono" }; /* * data that needs to be sent to device. sets up card internal stuff. @@ -327,14 +327,7 @@ static int usb6fire_control_input_vol_get(struct snd_kcontrol *kcontrol, static int usb6fire_control_line_phono_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item > 1) - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, - line_phono_texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 2, line_phono_texts); } static int usb6fire_control_line_phono_put(struct snd_kcontrol *kcontrol, @@ -361,14 +354,7 @@ static int usb6fire_control_line_phono_get(struct snd_kcontrol *kcontrol, static int usb6fire_control_opt_coax_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item > 1) - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, - opt_coax_texts[uinfo->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(uinfo, 1, 2, opt_coax_texts); } static int usb6fire_control_opt_coax_put(struct snd_kcontrol *kcontrol, -- cgit v1.2.3 From 7bbd03e0143b562ff7d96f7e71c016104020b550 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Oct 2014 18:21:42 +0200 Subject: ALSA: usb-audio: Use snd_ctl_enum_info() ... and reduce the open codes. Also add missing const to text arrays. Signed-off-by: Takashi Iwai --- sound/usb/mixer_quirks.c | 35 ++++++----------------------------- 1 file changed, 6 insertions(+), 29 deletions(-) (limited to 'sound') diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index f119a41ed9a9..3980bf554c83 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -437,19 +437,9 @@ static void snd_audigy2nx_proc_read(struct snd_info_entry *entry, static int snd_emu0204_ch_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static const char *texts[2] = {"1/2", - "3/4" - }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item > 1) - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); + static const char * const texts[2] = {"1/2", "3/4"}; - return 0; + return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); } static int snd_emu0204_ch_switch_get(struct snd_kcontrol *kcontrol, @@ -735,25 +725,12 @@ struct snd_ftu_eff_switch_priv_val { static int snd_ftu_eff_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static const char *texts[8] = {"Room 1", - "Room 2", - "Room 3", - "Hall 1", - "Hall 2", - "Plate", - "Delay", - "Echo" + static const char *const texts[8] = { + "Room 1", "Room 2", "Room 3", "Hall 1", + "Hall 2", "Plate", "Delay", "Echo" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 8; - if (uinfo->value.enumerated.item > 7) - uinfo->value.enumerated.item = 7; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - - return 0; + return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); } static int snd_ftu_eff_switch_get(struct snd_kcontrol *kctl, -- cgit v1.2.3 From cf6814f2b5014ed5bbdef764a42e4abaa09b3a2e Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Tue, 21 Oct 2014 16:28:47 +0530 Subject: ALSA: ctxfi: remove unused variable As of now the pointer to struct dai is not being used anywhere in the function. So it is safe to remove the variable. If we are ever doing anything with the container_of(daio, struct dai, daio), then at that time we can again add the variable. Signed-off-by: Sudip Mukherjee Signed-off-by: Takashi Iwai --- sound/pci/ctxfi/ctatc.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'sound') diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index 454659074390..632e843fa95e 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -1145,7 +1145,6 @@ static int atc_release_resources(struct ct_atc *atc) int i; struct daio_mgr *daio_mgr = NULL; struct dao *dao = NULL; - struct dai *dai = NULL; struct daio *daio = NULL; struct sum_mgr *sum_mgr = NULL; struct src_mgr *src_mgr = NULL; @@ -1172,9 +1171,6 @@ static int atc_release_resources(struct ct_atc *atc) dao = container_of(daio, struct dao, daio); dao->ops->clear_left_input(dao); dao->ops->clear_right_input(dao); - } else { - dai = container_of(daio, struct dai, daio); - /* some thing to do for dai ... */ } daio_mgr->put_daio(daio_mgr, daio); } -- cgit v1.2.3 From c37de55efa1ccf018c27b876560725ff5e9f5701 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 22 Oct 2014 12:01:13 +0200 Subject: ALSA: pcm: Remove arch-dependent mmap kludges Since we have consistently dma_mmap_coherent() for all architectures, the current ifdef and arch-specific codes in pcm core can be cleaned up gracefully. Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 30 ------------------------------ 1 file changed, 30 deletions(-) (limited to 'sound') diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 815396d8427f..aa6754da7929 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -35,9 +35,6 @@ #include #include #include -#if defined(CONFIG_MIPS) && defined(CONFIG_DMA_NONCOHERENT) -#include -#endif /* * Compatibility @@ -3251,20 +3248,6 @@ static inline struct page * snd_pcm_default_page_ops(struct snd_pcm_substream *substream, unsigned long ofs) { void *vaddr = substream->runtime->dma_area + ofs; -#if defined(CONFIG_MIPS) && defined(CONFIG_DMA_NONCOHERENT) - if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV) - return virt_to_page(CAC_ADDR(vaddr)); -#endif -#if defined(CONFIG_PPC32) && defined(CONFIG_NOT_COHERENT_CACHE) - if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV) { - dma_addr_t addr = substream->runtime->dma_addr + ofs; - addr -= get_dma_offset(substream->dma_buffer.dev.dev); - /* assume dma_handle set via pfn_to_phys() in - * mm/dma-noncoherent.c - */ - return pfn_to_page(addr >> PAGE_SHIFT); - } -#endif return virt_to_page(vaddr); } @@ -3309,13 +3292,6 @@ static const struct vm_operations_struct snd_pcm_vm_ops_data_fault = { .fault = snd_pcm_mmap_data_fault, }; -#ifndef ARCH_HAS_DMA_MMAP_COHERENT -/* This should be defined / handled globally! */ -#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) -#define ARCH_HAS_DMA_MMAP_COHERENT -#endif -#endif - /* * mmap the DMA buffer on RAM */ @@ -3331,7 +3307,6 @@ int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream, area->vm_end - area->vm_start, area->vm_page_prot); } #endif /* CONFIG_GENERIC_ALLOCATOR */ -#ifdef ARCH_HAS_DMA_MMAP_COHERENT if (!substream->ops->page && substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV) return dma_mmap_coherent(substream->dma_buffer.dev.dev, @@ -3339,11 +3314,6 @@ int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream, substream->runtime->dma_area, substream->runtime->dma_addr, area->vm_end - area->vm_start); -#elif defined(CONFIG_MIPS) && defined(CONFIG_DMA_NONCOHERENT) - if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV && - !plat_device_is_coherent(substream->dma_buffer.dev.dev)) - area->vm_page_prot = pgprot_noncached(area->vm_page_prot); -#endif /* ARCH_HAS_DMA_MMAP_COHERENT */ /* mmap with fault handler */ area->vm_ops = &snd_pcm_vm_ops_data_fault; return 0; -- cgit v1.2.3 From 63825f3a879ea2be569471643bb6aac73d9261f0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 22 Oct 2014 12:04:46 +0200 Subject: ALSA: pcm: Disable mmap for known broken archs Some architectures like PARISC is known not to support mmap properly with the DMA buffer, where dma_mmap_coherent() returns -EINVAL unconditionally. From the API POV, we should rather drop the mmap support there and expose it before the user-space tries to call mmap. The patch contains again ugly ifdef's, unfortunately, as there is no global flag indicating this. Once when such macro is defined, we can get rid of this instead. Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index aa6754da7929..dc9a1355a4ab 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -192,6 +192,21 @@ int snd_pcm_info_user(struct snd_pcm_substream *substream, return err; } +static bool hw_support_mmap(struct snd_pcm_substream *substream) +{ + if (!(substream->runtime->hw.info & SNDRV_PCM_INFO_MMAP)) + return false; + /* check architectures that return -EINVAL from dma_mmap_coherent() */ + /* FIXME: this should be some global flag */ +#if defined(CONFIG_C6X) || defined(CONFIG_FRV) || defined(CONFIG_MN10300) ||\ + defined(CONFIG_PARISC) || defined(CONFIG_XTENSA) + if (!substream->ops->mmap && + substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV) + return false; +#endif + return true; +} + #undef RULES_DEBUG #ifdef RULES_DEBUG @@ -369,8 +384,12 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, } hw = &substream->runtime->hw; - if (!params->info) + if (!params->info) { params->info = hw->info & ~SNDRV_PCM_INFO_FIFO_IN_FRAMES; + if (!hw_support_mmap(substream)) + params->info &= ~(SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID); + } if (!params->fifo_size) { m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); @@ -2069,7 +2088,7 @@ int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream) mask |= 1 << SNDRV_PCM_ACCESS_RW_INTERLEAVED; if (hw->info & SNDRV_PCM_INFO_NONINTERLEAVED) mask |= 1 << SNDRV_PCM_ACCESS_RW_NONINTERLEAVED; - if (hw->info & SNDRV_PCM_INFO_MMAP) { + if (hw_support_mmap(substream)) { if (hw->info & SNDRV_PCM_INFO_INTERLEAVED) mask |= 1 << SNDRV_PCM_ACCESS_MMAP_INTERLEAVED; if (hw->info & SNDRV_PCM_INFO_NONINTERLEAVED) -- cgit v1.2.3 From 49d776ffb50f2e428aafb6a6576e58e80f1e886c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 24 Oct 2014 12:36:23 +0200 Subject: ALSA: pcm: Avoid mmap warnings on x86 On x86, using dma_mmap_coherent() for the pages allocated via dma_alloc_coherent() results in a warning like: aplay:32536 map pfn RAM range req uncached-minus for [mem 0x21d500000-0x21d51ffff], got write-back Until the issue is addressed in the core side, take back to the old good way in PCM code only for x86. Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index dc9a1355a4ab..03e1e920ab13 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -3326,6 +3326,7 @@ int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream, area->vm_end - area->vm_start, area->vm_page_prot); } #endif /* CONFIG_GENERIC_ALLOCATOR */ +#ifndef CONFIG_X86 /* for avoiding warnings arch/x86/mm/pat.c */ if (!substream->ops->page && substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV) return dma_mmap_coherent(substream->dma_buffer.dev.dev, @@ -3333,6 +3334,7 @@ int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream, substream->runtime->dma_area, substream->runtime->dma_addr, area->vm_end - area->vm_start); +#endif /* CONFIG_X86 */ /* mmap with fault handler */ area->vm_ops = &snd_pcm_vm_ops_data_fault; return 0; -- cgit v1.2.3 From 66797f36fd17e8975f4a3449aed895cda952c0ce Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 27 Oct 2014 15:15:44 +0100 Subject: ALSA: hda - Pass printf argument directly to request_module() request_module() handles the printf style arguments, so we don't have to render strings in the caller side. Not only it reduces the unnecessary temporary string buffer, it's even safer from the security POV. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 259fbeaa37bd..0025bf4c2f44 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -966,14 +966,12 @@ find_codec_preset(struct hda_codec *codec) mutex_unlock(&preset_mutex); if (mod_requested < HDA_MODREQ_MAX_COUNT) { - char name[32]; if (!mod_requested) - snprintf(name, sizeof(name), "snd-hda-codec-id:%08x", - codec->vendor_id); + request_module("snd-hda-codec-id:%08x", + codec->vendor_id); else - snprintf(name, sizeof(name), "snd-hda-codec-id:%04x*", - (codec->vendor_id >> 16) & 0xffff); - request_module(name); + request_module("snd-hda-codec-id:%04x*", + (codec->vendor_id >> 16) & 0xffff); mod_requested++; goto again; } -- cgit v1.2.3 From 326f0480b7f8504c4f594c4f36ab7874e17780bc Mon Sep 17 00:00:00 2001 From: Aya Mahfouz Date: Tue, 28 Oct 2014 14:27:44 +0200 Subject: ALSA: pcxhr: convert timeval to ktime_t This patch is concerned with migrating the time variables in the pcxhr module found in the sound driver. The changes are concerend with the y2038 problem where timeval will overflow in the year 2038. ktime_t was used instead of timeval to get the wall time. The difference is displayed now in nanoseconds instead of microseconds. Signed-off-by: Aya Mahfouz Reviewed-by: Arnd Bergmann Signed-off-by: Takashi Iwai --- sound/pci/pcxhr/pcxhr.c | 10 ++++++---- sound/pci/pcxhr/pcxhr_core.c | 10 ++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c index b854fc5e01f5..7c33c973dbd5 100644 --- a/sound/pci/pcxhr/pcxhr.c +++ b/sound/pci/pcxhr/pcxhr.c @@ -711,8 +711,9 @@ static void pcxhr_start_linked_stream(struct pcxhr_mgr *mgr) int playback_mask = 0; #ifdef CONFIG_SND_DEBUG_VERBOSE - struct timeval my_tv1, my_tv2; - do_gettimeofday(&my_tv1); + ktime_t start_time, stop_time, diff_time; + + start_time = ktime_get(); #endif mutex_lock(&mgr->setup_mutex); @@ -823,9 +824,10 @@ static void pcxhr_start_linked_stream(struct pcxhr_mgr *mgr) mutex_unlock(&mgr->setup_mutex); #ifdef CONFIG_SND_DEBUG_VERBOSE - do_gettimeofday(&my_tv2); + stop_time = ktime_get(); + diff_time = ktime_sub(stop_time, start_time); dev_dbg(&mgr->pci->dev, "***TRIGGER START*** TIME = %ld (err = %x)\n", - (long)(my_tv2.tv_usec - my_tv1.tv_usec), err); + (long)(ktime_to_ns(diff_time)), err); #endif } diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c index a584acb61c00..181f7729d409 100644 --- a/sound/pci/pcxhr/pcxhr_core.c +++ b/sound/pci/pcxhr/pcxhr_core.c @@ -910,8 +910,9 @@ int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask, int audio_mask; #ifdef CONFIG_SND_DEBUG_VERBOSE - struct timeval my_tv1, my_tv2; - do_gettimeofday(&my_tv1); + ktime_t start_time, stop_time, diff_time; + + start_time = ktime_get(); #endif audio_mask = (playback_mask | (capture_mask << PCXHR_PIPE_STATE_CAPTURE_OFFSET)); @@ -960,9 +961,10 @@ int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask, return err; } #ifdef CONFIG_SND_DEBUG_VERBOSE - do_gettimeofday(&my_tv2); + stop_time = ktime_get(); + diff_time = ktime_sub(stop_time, start_time); dev_dbg(&mgr->pci->dev, "***SET PIPE STATE*** TIME = %ld (err = %x)\n", - (long)(my_tv2.tv_usec - my_tv1.tv_usec), err); + (long)(ktime_to_ns(diff_time)), err); #endif return 0; } -- cgit v1.2.3 From 2e6705c09065ecb357140e44d12dc32274b1a723 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 28 Oct 2014 17:16:51 +0100 Subject: ALSA: ctxfi: Kill the rest snd_print*() Use the standard dev_*() instead. Signed-off-by: Takashi Iwai --- sound/pci/ctxfi/ctatc.c | 6 ++++-- sound/pci/ctxfi/cttimer.c | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index 632e843fa95e..977a59855fa6 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -438,7 +438,9 @@ atc_pcm_playback_position(struct ct_atc *atc, struct ct_atc_pcm *apcm) position = src->ops->get_ca(src); if (position < apcm->vm_block->addr) { - snd_printdd("ctxfi: bad ca - ca=0x%08x, vba=0x%08x, vbs=0x%08x\n", position, apcm->vm_block->addr, apcm->vm_block->size); + dev_dbg(atc->card->dev, + "bad ca - ca=0x%08x, vba=0x%08x, vbs=0x%08x\n", + position, apcm->vm_block->addr, apcm->vm_block->size); position = apcm->vm_block->addr; } @@ -1295,7 +1297,7 @@ static int atc_identify_card(struct ct_atc *atc, unsigned int ssid) atc->model = CT20K2_UNKNOWN; } atc->model_name = ct_subsys_name[atc->model]; - snd_printd("ctxfi: chip %s model %s (%04x:%04x) is found\n", + dev_info(atc->card->dev, "chip %s model %s (%04x:%04x) is found\n", atc->chip_name, atc->model_name, vendor_id, device_id); return 0; diff --git a/sound/pci/ctxfi/cttimer.c b/sound/pci/ctxfi/cttimer.c index 03fb909085af..a5d460453d7b 100644 --- a/sound/pci/ctxfi/cttimer.c +++ b/sound/pci/ctxfi/cttimer.c @@ -421,12 +421,12 @@ struct ct_timer *ct_timer_new(struct ct_atc *atc) atimer->atc = atc; hw = atc->hw; if (!use_system_timer && hw->set_timer_irq) { - snd_printd(KERN_INFO "ctxfi: Use xfi-native timer\n"); + dev_info(atc->card->dev, "Use xfi-native timer\n"); atimer->ops = &ct_xfitimer_ops; hw->irq_callback_data = atimer; hw->irq_callback = ct_timer_interrupt; } else { - snd_printd(KERN_INFO "ctxfi: Use system timer\n"); + dev_info(atc->card->dev, "Use system timer\n"); atimer->ops = &ct_systimer_ops; } return atimer; -- cgit v1.2.3 From f48a6df28239f5bf35d80e43e580261d2298395a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 28 Oct 2014 17:22:45 +0100 Subject: ALSA: pcxhr: Kill the rest snd_print*() Use the standard dev_*() instead. Signed-off-by: Takashi Iwai --- sound/pci/pcxhr/pcxhr.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) (limited to 'sound') diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c index 7c33c973dbd5..a60293015267 100644 --- a/sound/pci/pcxhr/pcxhr.c +++ b/sound/pci/pcxhr/pcxhr.c @@ -501,10 +501,10 @@ int pcxhr_get_external_clock(struct pcxhr_mgr *mgr, /* * start or stop playback/capture substream */ -static int pcxhr_set_stream_state(struct pcxhr_stream *stream) +static int pcxhr_set_stream_state(struct snd_pcxhr *chip, + struct pcxhr_stream *stream) { int err; - struct snd_pcxhr *chip; struct pcxhr_rmh rmh; int stream_mask, start; @@ -512,8 +512,8 @@ static int pcxhr_set_stream_state(struct pcxhr_stream *stream) start = 1; else { if (stream->status != PCXHR_STREAM_STATUS_SCHEDULE_STOP) { - snd_printk(KERN_ERR "ERROR pcxhr_set_stream_state " - "CANNOT be stopped\n"); + dev_err(chip->card->dev, + "pcxhr_set_stream_state CANNOT be stopped\n"); return -EINVAL; } start = 0; @@ -560,6 +560,7 @@ static int pcxhr_set_format(struct pcxhr_stream *stream) struct pcxhr_rmh rmh; unsigned int header; + chip = snd_pcm_substream_chip(stream->substream); switch (stream->format) { case SNDRV_PCM_FORMAT_U8: header = HEADER_FMT_BASE_LIN; @@ -582,11 +583,10 @@ static int pcxhr_set_format(struct pcxhr_stream *stream) header = HEADER_FMT_BASE_FLOAT | HEADER_FMT_INTEL; break; default: - snd_printk(KERN_ERR - "error pcxhr_set_format() : unknown format\n"); + dev_err(chip->card->dev, + "error pcxhr_set_format() : unknown format\n"); return -EINVAL; } - chip = snd_pcm_substream_chip(stream->substream); sample_rate = chip->mgr->sample_rate; if (sample_rate <= 32000 && sample_rate !=0) { @@ -643,11 +643,11 @@ static int pcxhr_update_r_buffer(struct pcxhr_stream *stream) is_capture = (subs->stream == SNDRV_PCM_STREAM_CAPTURE); stream_num = is_capture ? 0 : subs->number; - snd_printdd("pcxhr_update_r_buffer(pcm%c%d) : " - "addr(%p) bytes(%zx) subs(%d)\n", - is_capture ? 'c' : 'p', - chip->chip_idx, (void *)(long)subs->runtime->dma_addr, - subs->runtime->dma_bytes, subs->number); + dev_dbg(chip->card->dev, + "pcxhr_update_r_buffer(pcm%c%d) : addr(%p) bytes(%zx) subs(%d)\n", + is_capture ? 'c' : 'p', + chip->chip_idx, (void *)(long)subs->runtime->dma_addr, + subs->runtime->dma_bytes, subs->number); pcxhr_init_rmh(&rmh, CMD_UPDATE_R_BUFFERS); pcxhr_set_pipe_cmd_params(&rmh, is_capture, stream->pipe->first_audio, @@ -687,7 +687,7 @@ static int pcxhr_pipe_sample_count(struct pcxhr_stream *stream, *sample_count = ((snd_pcm_uframes_t)rmh.stat[0]) << 24; *sample_count += (snd_pcm_uframes_t)rmh.stat[1]; } - snd_printdd("PIPE_SAMPLE_COUNT = %lx\n", *sample_count); + dev_dbg(chip->card->dev, "PIPE_SAMPLE_COUNT = %lx\n", *sample_count); return err; } #endif @@ -779,12 +779,12 @@ static void pcxhr_start_linked_stream(struct pcxhr_mgr *mgr) for (j = 0; j < chip->nb_streams_capt; j++) { stream = &chip->capture_stream[j]; if (pcxhr_stream_scheduled_get_pipe(stream, &pipe)) - err = pcxhr_set_stream_state(stream); + err = pcxhr_set_stream_state(chip, stream); } for (j = 0; j < chip->nb_streams_play; j++) { stream = &chip->playback_stream[j]; if (pcxhr_stream_scheduled_get_pipe(stream, &pipe)) - err = pcxhr_set_stream_state(stream); + err = pcxhr_set_stream_state(chip, stream); } } @@ -839,12 +839,12 @@ static int pcxhr_trigger(struct snd_pcm_substream *subs, int cmd) { struct pcxhr_stream *stream; struct snd_pcm_substream *s; + struct snd_pcxhr *chip = snd_pcm_substream_chip(subs); switch (cmd) { case SNDRV_PCM_TRIGGER_START: - snd_printdd("SNDRV_PCM_TRIGGER_START\n"); + dev_dbg(chip->card->dev, "SNDRV_PCM_TRIGGER_START\n"); if (snd_pcm_stream_linked(subs)) { - struct snd_pcxhr *chip = snd_pcm_substream_chip(subs); snd_pcm_group_for_each_entry(s, subs) { if (snd_pcm_substream_chip(s) != chip) continue; @@ -856,7 +856,7 @@ static int pcxhr_trigger(struct snd_pcm_substream *subs, int cmd) pcxhr_start_linked_stream(chip->mgr); } else { stream = subs->runtime->private_data; - snd_printdd("Only one Substream %c %d\n", + dev_dbg(chip->card->dev, "Only one Substream %c %d\n", stream->pipe->is_capture ? 'C' : 'P', stream->pipe->first_audio); if (pcxhr_set_format(stream)) @@ -865,17 +865,17 @@ static int pcxhr_trigger(struct snd_pcm_substream *subs, int cmd) return -EINVAL; stream->status = PCXHR_STREAM_STATUS_SCHEDULE_RUN; - if (pcxhr_set_stream_state(stream)) + if (pcxhr_set_stream_state(chip, stream)) return -EINVAL; stream->status = PCXHR_STREAM_STATUS_RUNNING; } break; case SNDRV_PCM_TRIGGER_STOP: - snd_printdd("SNDRV_PCM_TRIGGER_STOP\n"); + dev_dbg(chip->card->dev, "SNDRV_PCM_TRIGGER_STOP\n"); snd_pcm_group_for_each_entry(s, subs) { stream = s->runtime->private_data; stream->status = PCXHR_STREAM_STATUS_SCHEDULE_STOP; - if (pcxhr_set_stream_state(stream)) + if (pcxhr_set_stream_state(chip, stream)) return -EINVAL; snd_pcm_trigger_done(s, subs); } -- cgit v1.2.3 From f994cb3a09a5f2018c286f854c10277132f4a9a5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 28 Oct 2014 17:36:50 +0100 Subject: ALSA: au88x0: Kill the rest snd_print*() Use the standard dev_*() instead. Signed-off-by: Takashi Iwai --- sound/pci/au88x0/au88x0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c index e9c3833f6d44..996369134ea8 100644 --- a/sound/pci/au88x0/au88x0.c +++ b/sound/pci/au88x0/au88x0.c @@ -314,7 +314,7 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) if (snd_seq_device_new(card, 1, SNDRV_SEQ_DEV_ID_VORTEX_SYNTH, sizeof(snd_vortex_synth_arg_t), &wave) < 0 || wave == NULL) { - snd_printk(KERN_ERR "Can't initialize Aureal wavetable synth\n"); + dev_err(card->dev, "Can't initialize Aureal wavetable synth\n"); } else { snd_vortex_synth_arg_t *arg; -- cgit v1.2.3 From a11e9b168646cfc5d3b8d605d430d7e4ff267d72 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 29 Oct 2014 15:06:01 +0100 Subject: ALSA: hda - Correct kerneldoc comments Complete the missing parameters and fix anything wrong there. Just comment changes. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_auto_parser.c | 15 +++++- sound/pci/hda/hda_codec.c | 114 ++++++++++++++++++++++++++++++++++++++-- sound/pci/hda/hda_eld.c | 2 +- sound/pci/hda/hda_jack.c | 21 ++++++++ 4 files changed, 146 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index fcc5e478c9a1..7388958b01af 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c @@ -464,8 +464,12 @@ EXPORT_SYMBOL_GPL(snd_hda_get_input_pin_attr); /** * hda_get_input_pin_label - Give a label for the given input pin + * @codec: the HDA codec + * @item: ping config item to refer + * @pin: the pin NID + * @check_location: flag to add the jack location prefix * - * When check_location is true, the function checks the pin location + * When @check_location is true, the function checks the pin location * for mic and line-in pins, and set an appropriate prefix like "Front", * "Rear", "Internal". */ @@ -550,6 +554,9 @@ static int check_mic_location_need(struct hda_codec *codec, /** * hda_get_autocfg_input_label - Get a label for the given input + * @codec: the HDA codec + * @cfg: the parsed pin configuration + * @input: the input index number * * Get a label for the given input pin defined by the autocfg item. * Unlike hda_get_input_pin_label(), this function checks all inputs @@ -677,6 +684,12 @@ static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid, /** * snd_hda_get_pin_label - Get a label for the given I/O pin + * @codec: the HDA codec + * @nid: pin NID + * @cfg: the parsed pin configuration + * @label: the string buffer to store + * @maxlen: the max length of string buffer (including termination) + * @indexp: the pointer to return the index number (for multiple ctls) * * Get a label for the given pin. This function works for both input and * output pins. When @cfg is given as non-NULL, the function tries to get diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 0025bf4c2f44..e15254204c72 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -416,7 +416,6 @@ static int read_and_add_raw_conns(struct hda_codec *codec, hda_nid_t nid) * snd_hda_get_conn_list - get connection list * @codec: the HDA codec * @nid: NID to parse - * @len: number of connection list entries * @listp: the pointer to store NID list * * Parses the connection list of the given widget and stores the pointer @@ -2004,6 +2003,7 @@ EXPORT_SYMBOL_GPL(query_amp_caps); * @codec: the HD-audio codec * @nid: the NID to query * @dir: either #HDA_INPUT or #HDA_OUTPUT + * @bits: bit mask to check the result * * Check whether the widget has the given amp capability for the direction. */ @@ -2023,7 +2023,7 @@ EXPORT_SYMBOL_GPL(snd_hda_check_amp_caps); * snd_hda_override_amp_caps - Override the AMP capabilities * @codec: the CODEC to clean up * @nid: the NID to clean up - * @direction: either #HDA_INPUT or #HDA_OUTPUT + * @dir: either #HDA_INPUT or #HDA_OUTPUT * @caps: the capability bits to set * * Override the cached AMP caps bits value by the given one. @@ -2320,6 +2320,8 @@ static u32 get_amp_max_value(struct hda_codec *codec, hda_nid_t nid, int dir, /** * snd_hda_mixer_amp_volume_info - Info callback for a standard AMP mixer + * @kcontrol: referred ctl element + * @uinfo: pointer to get/store the data * * The control element is supposed to have the private_value field * set up via HDA_COMPOSE_AMP_VAL*() or related macros. @@ -2381,6 +2383,8 @@ update_amp_value(struct hda_codec *codec, hda_nid_t nid, /** * snd_hda_mixer_amp_volume_get - Get callback for a standard AMP mixer volume + * @kcontrol: ctl element + * @ucontrol: pointer to get/store the data * * The control element is supposed to have the private_value field * set up via HDA_COMPOSE_AMP_VAL*() or related macros. @@ -2406,6 +2410,8 @@ EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_get); /** * snd_hda_mixer_amp_volume_put - Put callback for a standard AMP mixer volume + * @kcontrol: ctl element + * @ucontrol: pointer to get/store the data * * The control element is supposed to have the private_value field * set up via HDA_COMPOSE_AMP_VAL*() or related macros. @@ -2436,6 +2442,10 @@ EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_put); /** * snd_hda_mixer_amp_volume_put - TLV callback for a standard AMP mixer volume + * @kcontrol: ctl element + * @op_flag: operation flag + * @size: byte size of input TLV + * @_tlv: TLV data * * The control element is supposed to have the private_value field * set up via HDA_COMPOSE_AMP_VAL*() or related macros. @@ -3012,6 +3022,8 @@ EXPORT_SYMBOL_GPL(snd_hda_sync_vmaster_hook); /** * snd_hda_mixer_amp_switch_info - Info callback for a standard AMP mixer switch + * @kcontrol: referred ctl element + * @uinfo: pointer to get/store the data * * The control element is supposed to have the private_value field * set up via HDA_COMPOSE_AMP_VAL*() or related macros. @@ -3031,6 +3043,8 @@ EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_info); /** * snd_hda_mixer_amp_switch_get - Get callback for a standard AMP mixer switch + * @kcontrol: ctl element + * @ucontrol: pointer to get/store the data * * The control element is supposed to have the private_value field * set up via HDA_COMPOSE_AMP_VAL*() or related macros. @@ -3057,6 +3071,8 @@ EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_get); /** * snd_hda_mixer_amp_switch_put - Put callback for a standard AMP mixer switch + * @kcontrol: ctl element + * @ucontrol: pointer to get/store the data * * The control element is supposed to have the private_value field * set up via HDA_COMPOSE_AMP_VAL*() or related macros. @@ -3100,6 +3116,8 @@ EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_put); /** * snd_hda_mixer_bind_switch_get - Get callback for a bound volume control + * @kcontrol: ctl element + * @ucontrol: pointer to get/store the data * * The control element is supposed to have the private_value field * set up via HDA_BIND_MUTE*() macros. @@ -3123,6 +3141,8 @@ EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_switch_get); /** * snd_hda_mixer_bind_switch_put - Put callback for a bound volume control + * @kcontrol: ctl element + * @ucontrol: pointer to get/store the data * * The control element is supposed to have the private_value field * set up via HDA_BIND_MUTE*() macros. @@ -3153,6 +3173,8 @@ EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_switch_put); /** * snd_hda_mixer_bind_ctls_info - Info callback for a generic bound control + * @kcontrol: referred ctl element + * @uinfo: pointer to get/store the data * * The control element is supposed to have the private_value field * set up via HDA_BIND_VOL() or HDA_BIND_SW() macros. @@ -3176,6 +3198,8 @@ EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_ctls_info); /** * snd_hda_mixer_bind_ctls_get - Get callback for a generic bound control + * @kcontrol: ctl element + * @ucontrol: pointer to get/store the data * * The control element is supposed to have the private_value field * set up via HDA_BIND_VOL() or HDA_BIND_SW() macros. @@ -3199,6 +3223,8 @@ EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_ctls_get); /** * snd_hda_mixer_bind_ctls_put - Put callback for a generic bound control + * @kcontrol: ctl element + * @ucontrol: pointer to get/store the data * * The control element is supposed to have the private_value field * set up via HDA_BIND_VOL() or HDA_BIND_SW() macros. @@ -3228,6 +3254,10 @@ EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_ctls_put); /** * snd_hda_mixer_bind_tlv - TLV callback for a generic bound control + * @kcontrol: ctl element + * @op_flag: operation flag + * @size: byte size of input TLV + * @tlv: TLV data * * The control element is supposed to have the private_value field * set up via HDA_BIND_VOL() macro. @@ -4305,6 +4335,7 @@ static struct hda_rate_tbl rate_bits[] = { * @channels: the number of channels * @format: the PCM format (SNDRV_PCM_FORMAT_XXX) * @maxbps: the max. bps + * @spdif_ctls: HD-audio SPDIF status bits (0 if irrelevant) * * Calculate the format bitset from the given rate, channels and th PCM format. * @@ -4980,6 +5011,7 @@ static void __snd_hda_power_down(struct hda_codec *codec) * snd_hda_power_save - Power-up/down/sync the codec * @codec: HD-audio codec * @delta: the counter delta to change + * @d3wait: sync for D3 transition complete * * Change the power-up counter via @delta, and power up or down the hardware * appropriately. For the power-down, queue to the delayed action. @@ -5055,6 +5087,10 @@ EXPORT_SYMBOL_GPL(snd_hda_check_amp_list_power); /** * snd_hda_ch_mode_info - Info callback helper for the channel mode enum + * @codec: the HDA codec + * @uinfo: pointer to get/store the data + * @chmode: channel mode array + * @num_chmodes: channel mode array size */ int snd_hda_ch_mode_info(struct hda_codec *codec, struct snd_ctl_elem_info *uinfo, @@ -5074,6 +5110,11 @@ EXPORT_SYMBOL_GPL(snd_hda_ch_mode_info); /** * snd_hda_ch_mode_get - Get callback helper for the channel mode enum + * @codec: the HDA codec + * @ucontrol: pointer to get/store the data + * @chmode: channel mode array + * @num_chmodes: channel mode array size + * @max_channels: max number of channels */ int snd_hda_ch_mode_get(struct hda_codec *codec, struct snd_ctl_elem_value *ucontrol, @@ -5095,6 +5136,11 @@ EXPORT_SYMBOL_GPL(snd_hda_ch_mode_get); /** * snd_hda_ch_mode_put - Put callback helper for the channel mode enum + * @codec: the HDA codec + * @ucontrol: pointer to get/store the data + * @chmode: channel mode array + * @num_chmodes: channel mode array size + * @max_channelsp: pointer to store the max channels */ int snd_hda_ch_mode_put(struct hda_codec *codec, struct snd_ctl_elem_value *ucontrol, @@ -5123,6 +5169,8 @@ EXPORT_SYMBOL_GPL(snd_hda_ch_mode_put); /** * snd_hda_input_mux_info_info - Info callback helper for the input-mux enum + * @imux: imux helper object + * @uinfo: pointer to get/store the data */ int snd_hda_input_mux_info(const struct hda_input_mux *imux, struct snd_ctl_elem_info *uinfo) @@ -5144,6 +5192,11 @@ EXPORT_SYMBOL_GPL(snd_hda_input_mux_info); /** * snd_hda_input_mux_info_put - Put callback helper for the input-mux enum + * @codec: the HDA codec + * @imux: imux helper object + * @ucontrol: pointer to get/store the data + * @nid: input mux NID + * @cur_val: pointer to get/store the current imux value */ int snd_hda_input_mux_put(struct hda_codec *codec, const struct hda_input_mux *imux, @@ -5168,7 +5221,13 @@ int snd_hda_input_mux_put(struct hda_codec *codec, EXPORT_SYMBOL_GPL(snd_hda_input_mux_put); -/* +/** + * snd_hda_enum_helper_info - Helper for simple enum ctls + * @kcontrol: ctl element + * @uinfo: pointer to get/store the data + * @num_items: number of enum items + * @texts: enum item string array + * * process kcontrol info callback of a simple string enum array * when @num_items is 0 or @texts is NULL, assume a boolean enum array */ @@ -5257,6 +5316,8 @@ EXPORT_SYMBOL_GPL(snd_hda_bus_reboot_notify); /** * snd_hda_multi_out_dig_open - open the digital out in the exclusive mode + * @codec: the HDA codec + * @mout: hda_multi_out object */ int snd_hda_multi_out_dig_open(struct hda_codec *codec, struct hda_multi_out *mout) @@ -5273,6 +5334,11 @@ EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_open); /** * snd_hda_multi_out_dig_prepare - prepare the digital out stream + * @codec: the HDA codec + * @mout: hda_multi_out object + * @stream_tag: stream tag to assign + * @format: format id to assign + * @substream: PCM substream to assign */ int snd_hda_multi_out_dig_prepare(struct hda_codec *codec, struct hda_multi_out *mout, @@ -5289,6 +5355,8 @@ EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_prepare); /** * snd_hda_multi_out_dig_cleanup - clean-up the digital out stream + * @codec: the HDA codec + * @mout: hda_multi_out object */ int snd_hda_multi_out_dig_cleanup(struct hda_codec *codec, struct hda_multi_out *mout) @@ -5302,6 +5370,8 @@ EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_cleanup); /** * snd_hda_multi_out_dig_close - release the digital out stream + * @codec: the HDA codec + * @mout: hda_multi_out object */ int snd_hda_multi_out_dig_close(struct hda_codec *codec, struct hda_multi_out *mout) @@ -5315,6 +5385,10 @@ EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_close); /** * snd_hda_multi_out_analog_open - open analog outputs + * @codec: the HDA codec + * @mout: hda_multi_out object + * @substream: PCM substream to assign + * @hinfo: PCM information to assign * * Open analog outputs and set up the hw-constraints. * If the digital outputs can be opened as slave, open the digital @@ -5365,6 +5439,11 @@ EXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_open); /** * snd_hda_multi_out_analog_prepare - Preapre the analog outputs. + * @codec: the HDA codec + * @mout: hda_multi_out object + * @stream_tag: stream tag to assign + * @format: format id to assign + * @substream: PCM substream to assign * * Set up the i/o for analog out. * When the digital out is available, copy the front out to digital out, too. @@ -5442,6 +5521,8 @@ EXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_prepare); /** * snd_hda_multi_out_analog_cleanup - clean up the setting for analog out + * @codec: the HDA codec + * @mout: hda_multi_out object */ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, struct hda_multi_out *mout) @@ -5473,6 +5554,8 @@ EXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_cleanup); /** * snd_hda_get_default_vref - Get the default (mic) VREF pin bits + * @codec: the HDA codec + * @pin: referred pin NID * * Guess the suitable VREF pin bits to be set as the pin-control value. * Note: the function doesn't set the AC_PINCTL_IN_EN bit. @@ -5498,7 +5581,12 @@ unsigned int snd_hda_get_default_vref(struct hda_codec *codec, hda_nid_t pin) } EXPORT_SYMBOL_GPL(snd_hda_get_default_vref); -/* correct the pin ctl value for matching with the pin cap */ +/** + * snd_hda_correct_pin_ctl - correct the pin ctl value for matching with the pin cap + * @codec: the HDA codec + * @pin: referred pin NID + * @val: pin ctl value to audit + */ unsigned int snd_hda_correct_pin_ctl(struct hda_codec *codec, hda_nid_t pin, unsigned int val) { @@ -5549,6 +5637,19 @@ unsigned int snd_hda_correct_pin_ctl(struct hda_codec *codec, } EXPORT_SYMBOL_GPL(snd_hda_correct_pin_ctl); +/** + * _snd_hda_pin_ctl - Helper to set pin ctl value + * @codec: the HDA codec + * @pin: referred pin NID + * @val: pin control value to set + * @cached: access over codec pinctl cache or direct write + * + * This function is a helper to set a pin ctl value more safely. + * It corrects the pin ctl value via snd_hda_correct_pin_ctl(), stores the + * value in pin target array via snd_hda_codec_set_pin_target(), then + * actually writes the value via either snd_hda_codec_update_cache() or + * snd_hda_codec_write() depending on @cached flag. + */ int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin, unsigned int val, bool cached) { @@ -5565,6 +5666,11 @@ EXPORT_SYMBOL_GPL(_snd_hda_set_pin_ctl); /** * snd_hda_add_imux_item - Add an item to input_mux + * @codec: the HDA codec + * @imux: imux helper object + * @label: the name of imux item to assign + * @index: index number of imux item to assign + * @type_idx: pointer to store the resultant label index * * When the same label is used already in the existing items, the number * suffix is appended to the label. This label index number is stored diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index e1cd34d9011d..0e6d7534f491 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -371,7 +371,7 @@ error: return ret; } -/** +/* * SNDRV_PCM_RATE_* and AC_PAR_PCM values don't match, print correct rates with * hdmi-specific routine. */ diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index f56765ae73a7..b2d81ab22fb0 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -57,6 +57,8 @@ static u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid) /** * snd_hda_jack_tbl_get - query the jack-table entry for the given NID + * @codec: the HDA codec + * @nid: pin NID to refer to */ struct hda_jack_tbl * snd_hda_jack_tbl_get(struct hda_codec *codec, hda_nid_t nid) @@ -75,6 +77,8 @@ EXPORT_SYMBOL_GPL(snd_hda_jack_tbl_get); /** * snd_hda_jack_tbl_get_from_tag - query the jack-table entry for the given tag + * @codec: the HDA codec + * @tag: tag value to refer to */ struct hda_jack_tbl * snd_hda_jack_tbl_get_from_tag(struct hda_codec *codec, unsigned char tag) @@ -93,6 +97,8 @@ EXPORT_SYMBOL_GPL(snd_hda_jack_tbl_get_from_tag); /** * snd_hda_jack_tbl_new - create a jack-table entry for the given NID + * @codec: the HDA codec + * @nid: pin NID to assign */ static struct hda_jack_tbl * snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid) @@ -162,6 +168,7 @@ static void jack_detect_update(struct hda_codec *codec, /** * snd_hda_set_dirty_all - Mark all the cached as dirty + * @codec: the HDA codec * * This function sets the dirty flag to all entries of jack table. * It's called from the resume path in hda_codec.c. @@ -218,6 +225,9 @@ EXPORT_SYMBOL_GPL(snd_hda_jack_detect_state); /** * snd_hda_jack_detect_enable - enable the jack-detection + * @codec: the HDA codec + * @nid: pin NID to enable + * @func: callback function to register * * In the case of error, the return value will be a pointer embedded with * errno. Check and handle the return value appropriately with standard @@ -266,6 +276,9 @@ EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable); /** * snd_hda_jack_set_gating_jack - Set gating jack. + * @codec: the HDA codec + * @gated_nid: gated pin NID + * @gating_nid: gating pin NID * * Indicates the gated jack is only valid when the gating jack is plugged. */ @@ -287,6 +300,7 @@ EXPORT_SYMBOL_GPL(snd_hda_jack_set_gating_jack); /** * snd_hda_jack_report_sync - sync the states of all jacks and report if changed + * @codec: the HDA codec */ void snd_hda_jack_report_sync(struct hda_codec *codec) { @@ -349,6 +363,11 @@ static void hda_free_jack_priv(struct snd_jack *jack) /** * snd_hda_jack_add_kctl - Add a kctl for the given pin + * @codec: the HDA codec + * @nid: pin NID to assign + * @name: string name for the jack + * @idx: index number for the jack + * @phantom_jack: flag to deal as a phantom jack * * This assigns a jack-detection kctl to the given pin. The kcontrol * will have the given name and index. @@ -456,6 +475,8 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, /** * snd_hda_jack_add_kctls - Add kctls for all pins included in the given pincfg + * @codec: the HDA codec + * @cfg: pin config table to parse */ int snd_hda_jack_add_kctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) -- cgit v1.2.3 From 95a962c36f6e3c3edb438d1ba59e30964900d16a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 29 Oct 2014 16:03:58 +0100 Subject: ALSA: hda - More kerneldoc comments Put more kerneldoc comments to the exported functions. Still the generic parser code and the HD-audio controller code aren't covered yet, though. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_auto_parser.c | 51 +++++++++++++- sound/pci/hda/hda_beep.c | 38 +++++++++++ sound/pci/hda/hda_codec.c | 148 ++++++++++++++++++++++++++++++++++++---- sound/pci/hda/hda_jack.c | 39 +++++++++++ sound/pci/hda/hda_jack.h | 5 ++ sound/pci/hda/hda_sysfs.c | 35 ++++++++-- 6 files changed, 297 insertions(+), 19 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index 7388958b01af..1ede82200ee5 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c @@ -441,6 +441,13 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, } EXPORT_SYMBOL_GPL(snd_hda_parse_pin_defcfg); +/** + * snd_hda_get_input_pin_attr - Get the input pin attribute from pin config + * @def_conf: pin configuration value + * + * Guess the input pin attribute (INPUT_PIN_ATTR_XXX) from the given + * default pin configuration value. + */ int snd_hda_get_input_pin_attr(unsigned int def_conf) { unsigned int loc = get_defcfg_location(def_conf); @@ -473,7 +480,6 @@ EXPORT_SYMBOL_GPL(snd_hda_get_input_pin_attr); * for mic and line-in pins, and set an appropriate prefix like "Front", * "Rear", "Internal". */ - static const char *hda_get_input_pin_label(struct hda_codec *codec, const struct auto_pin_cfg_item *item, hda_nid_t pin, bool check_location) @@ -761,6 +767,14 @@ int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid, } EXPORT_SYMBOL_GPL(snd_hda_get_pin_label); +/** + * snd_hda_add_verbs - Add verbs to the init list + * @codec: the HDA codec + * @list: zero-terminated verb list to add + * + * Append the given verb list to the execution list. The verbs will be + * performed at init and resume time via snd_hda_apply_verbs(). + */ int snd_hda_add_verbs(struct hda_codec *codec, const struct hda_verb *list) { @@ -773,6 +787,10 @@ int snd_hda_add_verbs(struct hda_codec *codec, } EXPORT_SYMBOL_GPL(snd_hda_add_verbs); +/** + * snd_hda_apply_verbs - Execute the init verb lists + * @codec: the HDA codec + */ void snd_hda_apply_verbs(struct hda_codec *codec) { int i; @@ -783,6 +801,11 @@ void snd_hda_apply_verbs(struct hda_codec *codec) } EXPORT_SYMBOL_GPL(snd_hda_apply_verbs); +/** + * snd_hda_apply_pincfgs - Set each pin config in the given list + * @codec: the HDA codec + * @cfg: NULL-terminated pin config table + */ void snd_hda_apply_pincfgs(struct hda_codec *codec, const struct hda_pintbl *cfg) { @@ -850,6 +873,11 @@ static void apply_fixup(struct hda_codec *codec, int id, int action, int depth) } } +/** + * snd_hda_apply_fixup - Apply the fixup chain with the given action + * @codec: the HDA codec + * @action: fixup action (HDA_FIXUP_ACT_XXX) + */ void snd_hda_apply_fixup(struct hda_codec *codec, int action) { if (codec->fixup_list) @@ -868,6 +896,12 @@ static bool pin_config_match(struct hda_codec *codec, return true; } +/** + * snd_hda_pick_pin_fixup - Pick up a fixup matching with the pin quirk list + * @codec: the HDA codec + * @pin_quirk: zero-terminated pin quirk list + * @fixlist: the fixup list + */ void snd_hda_pick_pin_fixup(struct hda_codec *codec, const struct snd_hda_pin_quirk *pin_quirk, const struct hda_fixup *fixlist) @@ -894,6 +928,21 @@ void snd_hda_pick_pin_fixup(struct hda_codec *codec, } EXPORT_SYMBOL_GPL(snd_hda_pick_pin_fixup); +/** + * snd_hda_pick_fixup - Pick up a fixup matching with PCI/codec SSID or model string + * @codec: the HDA codec + * @models: NULL-terminated model string list + * @quirk: zero-terminated PCI/codec SSID quirk list + * @fixlist: the fixup list + * + * Pick up a fixup entry matching with the given model string or SSID. + * If a fixup was already set beforehand, the function doesn't do anything. + * When a special model string "nofixup" is given, also no fixup is applied. + * + * The function tries to find the matching model name at first, if given. + * If nothing matched, try to look up the PCI SSID. + * If still nothing matched, try to look up the codec SSID. + */ void snd_hda_pick_fixup(struct hda_codec *codec, const struct hda_model_fixup *models, const struct snd_pci_quirk *quirk, diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c index 8c6c50afc0b7..1e7de08e77cb 100644 --- a/sound/pci/hda/hda_beep.c +++ b/sound/pci/hda/hda_beep.c @@ -175,6 +175,11 @@ static int snd_hda_do_attach(struct hda_beep *beep) return 0; } +/** + * snd_hda_enable_beep_device - Turn on/off beep sound + * @codec: the HDA codec + * @enable: flag to turn on/off + */ int snd_hda_enable_beep_device(struct hda_codec *codec, int enable) { struct hda_beep *beep = codec->beep; @@ -191,6 +196,20 @@ int snd_hda_enable_beep_device(struct hda_codec *codec, int enable) } EXPORT_SYMBOL_GPL(snd_hda_enable_beep_device); +/** + * snd_hda_attach_beep_device - Attach a beep input device + * @codec: the HDA codec + * @nid: beep NID + * + * Attach a beep object to the given widget. If beep hint is turned off + * explicitly or beep_mode of the codec is turned off, this doesn't nothing. + * + * The attached beep device has to be registered via + * snd_hda_register_beep_device() and released via snd_hda_detach_beep_device() + * appropriately. + * + * Currently, only one beep device is allowed to each codec. + */ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) { struct hda_beep *beep; @@ -228,6 +247,10 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) } EXPORT_SYMBOL_GPL(snd_hda_attach_beep_device); +/** + * snd_hda_detach_beep_device - Detach the beep device + * @codec: the HDA codec + */ void snd_hda_detach_beep_device(struct hda_codec *codec) { struct hda_beep *beep = codec->beep; @@ -240,6 +263,10 @@ void snd_hda_detach_beep_device(struct hda_codec *codec) } EXPORT_SYMBOL_GPL(snd_hda_detach_beep_device); +/** + * snd_hda_register_beep_device - Register the beep device + * @codec: the HDA codec + */ int snd_hda_register_beep_device(struct hda_codec *codec) { struct hda_beep *beep = codec->beep; @@ -269,6 +296,12 @@ static bool ctl_has_mute(struct snd_kcontrol *kcontrol) } /* get/put callbacks for beep mute mixer switches */ + +/** + * snd_hda_mixer_amp_switch_get_beep - Get callback for beep controls + * @kcontrol: ctl element + * @ucontrol: pointer to get/store the data + */ int snd_hda_mixer_amp_switch_get_beep(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -283,6 +316,11 @@ int snd_hda_mixer_amp_switch_get_beep(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_get_beep); +/** + * snd_hda_mixer_amp_switch_put_beep - Put callback for beep controls + * @kcontrol: ctl element + * @ucontrol: pointer to get/store the data + */ int snd_hda_mixer_amp_switch_put_beep(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index e15254204c72..ca98f5209f8f 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -77,6 +77,10 @@ static struct hda_vendor_id hda_vendor_ids[] = { static DEFINE_MUTEX(preset_mutex); static LIST_HEAD(hda_preset_tables); +/** + * snd_hda_add_codec_preset - Add a codec preset to the chain + * @preset: codec preset table to add + */ int snd_hda_add_codec_preset(struct hda_codec_preset_list *preset) { mutex_lock(&preset_mutex); @@ -86,6 +90,10 @@ int snd_hda_add_codec_preset(struct hda_codec_preset_list *preset) } EXPORT_SYMBOL_GPL(snd_hda_add_codec_preset); +/** + * snd_hda_delete_codec_preset - Delete a codec preset from the chain + * @preset: codec preset table to delete + */ int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset) { mutex_lock(&preset_mutex); @@ -1187,7 +1195,16 @@ unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid) } EXPORT_SYMBOL_GPL(snd_hda_codec_get_pincfg); -/* remember the current pinctl target value */ +/** + * snd_hda_codec_set_pin_target - remember the current pinctl target value + * @codec: the HDA codec + * @nid: pin NID + * @val: assigned pinctl value + * + * This function stores the given value to a pinctl target value in the + * pincfg table. This isn't always as same as the actually written value + * but can be referred at any time via snd_hda_codec_get_pin_target(). + */ int snd_hda_codec_set_pin_target(struct hda_codec *codec, hda_nid_t nid, unsigned int val) { @@ -1201,7 +1218,11 @@ int snd_hda_codec_set_pin_target(struct hda_codec *codec, hda_nid_t nid, } EXPORT_SYMBOL_GPL(snd_hda_codec_set_pin_target); -/* return the current pinctl target value */ +/** + * snd_hda_codec_get_pin_target - return the current pinctl target value + * @codec: the HDA codec + * @nid: pin NID + */ int snd_hda_codec_get_pin_target(struct hda_codec *codec, hda_nid_t nid) { struct hda_pincfg *pin; @@ -1573,6 +1594,13 @@ int snd_hda_codec_new(struct hda_bus *bus, } EXPORT_SYMBOL_GPL(snd_hda_codec_new); +/** + * snd_hda_codec_update_widgets - Refresh widget caps and pin defaults + * @codec: the HDA codec + * + * Forcibly refresh the all widget caps and the init pin configurations of + * the given codec. + */ int snd_hda_codec_update_widgets(struct hda_codec *codec) { hda_nid_t fg; @@ -2239,7 +2267,17 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, } EXPORT_SYMBOL_GPL(snd_hda_codec_amp_stereo); -/* Works like snd_hda_codec_amp_update() but it writes the value only at +/** + * snd_hda_codec_amp_init - initialize the AMP value + * @codec: the HDA codec + * @nid: NID to read the AMP value + * @ch: channel (left=0 or right=1) + * @dir: #HDA_INPUT or #HDA_OUTPUT + * @idx: the index value (only for input direction) + * @mask: bit mask to set + * @val: the bits value to set + * + * Works like snd_hda_codec_amp_update() but it writes the value only at * the first access. If the amp was already initialized / updated beforehand, * this does nothing. */ @@ -2250,6 +2288,17 @@ int snd_hda_codec_amp_init(struct hda_codec *codec, hda_nid_t nid, int ch, } EXPORT_SYMBOL_GPL(snd_hda_codec_amp_init); +/** + * snd_hda_codec_amp_init_stereo - initialize the stereo AMP value + * @codec: the HDA codec + * @nid: NID to read the AMP value + * @dir: #HDA_INPUT or #HDA_OUTPUT + * @idx: the index value (only for input direction) + * @mask: bit mask to set + * @val: the bits value to set + * + * Call snd_hda_codec_amp_init() for both stereo channels. + */ int snd_hda_codec_amp_init_stereo(struct hda_codec *codec, hda_nid_t nid, int dir, int idx, int mask, int val) { @@ -2644,7 +2693,10 @@ void snd_hda_ctls_clear(struct hda_codec *codec) snd_array_free(&codec->nids); } -/* pseudo device locking +/** + * snd_hda_lock_devices - pseudo device locking + * @bus: the BUS + * * toggle card->shutdown to allow/disallow the device access (as a hack) */ int snd_hda_lock_devices(struct hda_bus *bus) @@ -2681,6 +2733,10 @@ int snd_hda_lock_devices(struct hda_bus *bus) } EXPORT_SYMBOL_GPL(snd_hda_lock_devices); +/** + * snd_hda_unlock_devices - pseudo device unlocking + * @bus: the BUS + */ void snd_hda_unlock_devices(struct hda_bus *bus) { struct snd_card *card = bus->card; @@ -2867,7 +2923,7 @@ static int add_slave(struct hda_codec *codec, } /** - * snd_hda_add_vmaster - create a virtual master control and add slaves + * __snd_hda_add_vmaster - create a virtual master control and add slaves * @codec: HD-audio codec * @name: vmaster control name * @tlv: TLV data (optional) @@ -2970,10 +3026,15 @@ static struct snd_kcontrol_new vmaster_mute_mode = { .put = vmaster_mute_mode_put, }; -/* - * Add a mute-LED hook with the given vmaster switch kctl - * "Mute-LED Mode" control is automatically created and associated with - * the given hook. +/** + * snd_hda_add_vmaster_hook - Add a vmaster hook for mute-LED + * @codec: the HDA codec + * @hook: the vmaster hook object + * @expose_enum_ctl: flag to create an enum ctl + * + * Add a mute-LED hook with the given vmaster switch kctl. + * When @expose_enum_ctl is set, "Mute-LED Mode" control is automatically + * created and associated with the given hook. */ int snd_hda_add_vmaster_hook(struct hda_codec *codec, struct hda_vmaster_mute_hook *hook, @@ -2995,9 +3056,12 @@ int snd_hda_add_vmaster_hook(struct hda_codec *codec, } EXPORT_SYMBOL_GPL(snd_hda_add_vmaster_hook); -/* - * Call the hook with the current value for synchronization - * Should be called in init callback +/** + * snd_hda_sync_vmaster_hook - Sync vmaster hook + * @hook: the vmaster hook + * + * Call the hook with the current value for synchronization. + * Should be called in init callback. */ void snd_hda_sync_vmaster_hook(struct hda_vmaster_mute_hook *hook) { @@ -3599,7 +3663,11 @@ int snd_hda_create_dig_out_ctls(struct hda_codec *codec, } EXPORT_SYMBOL_GPL(snd_hda_create_dig_out_ctls); -/* get the hda_spdif_out entry from the given NID +/** + * snd_hda_spdif_out_of_nid - get the hda_spdif_out entry from the given NID + * @codec: the HDA codec + * @nid: widget NID + * * call within spdif_mutex lock */ struct hda_spdif_out *snd_hda_spdif_out_of_nid(struct hda_codec *codec, @@ -3616,6 +3684,13 @@ struct hda_spdif_out *snd_hda_spdif_out_of_nid(struct hda_codec *codec, } EXPORT_SYMBOL_GPL(snd_hda_spdif_out_of_nid); +/** + * snd_hda_spdif_ctls_unassign - Unassign the given SPDIF ctl + * @codec: the HDA codec + * @idx: the SPDIF ctl index + * + * Unassign the widget from the given SPDIF control. + */ void snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx) { struct hda_spdif_out *spdif; @@ -3627,6 +3702,14 @@ void snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx) } EXPORT_SYMBOL_GPL(snd_hda_spdif_ctls_unassign); +/** + * snd_hda_spdif_ctls_assign - Assign the SPDIF controls to the given NID + * @codec: the HDA codec + * @idx: the SPDIF ctl idx + * @nid: widget NID + * + * Assign the widget to the SPDIF control with the given index. + */ void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid) { struct hda_spdif_out *spdif; @@ -3946,6 +4029,16 @@ void snd_hda_codec_flush_cache(struct hda_codec *codec) } EXPORT_SYMBOL_GPL(snd_hda_codec_flush_cache); +/** + * snd_hda_codec_set_power_to_all - Set the power state to all widgets + * @codec: the HDA codec + * @fg: function group (not used now) + * @power_state: the power state to set (AC_PWRST_*) + * + * Set the given power state to all widgets that have the power control. + * If the codec has power_filter set, it evaluates the power state and + * filter out if it's unchanged as D3. + */ void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg, unsigned int power_state) { @@ -4010,7 +4103,15 @@ static unsigned int hda_sync_power_state(struct hda_codec *codec, return state; } -/* don't power down the widget if it controls eapd and EAPD_BTLENABLE is set */ +/** + * snd_hda_codec_eapd_power_filter - A power filter callback for EAPD + * @codec: the HDA codec + * @nid: widget NID + * @power_state: power state to evalue + * + * Don't power down the widget if it controls eapd and EAPD_BTLENABLE is set. + * This can be used a codec power_filter callback. + */ unsigned int snd_hda_codec_eapd_power_filter(struct hda_codec *codec, hda_nid_t nid, unsigned int power_state) @@ -4671,6 +4772,17 @@ static int set_pcm_default_values(struct hda_codec *codec, /* * codec prepare/cleanup entries */ +/** + * snd_hda_codec_prepare - Prepare a stream + * @codec: the HDA codec + * @hinfo: PCM information + * @stream: stream tag to assign + * @format: format id to assign + * @substream: PCM substream to assign + * + * Calls the prepare callback set by the codec with the given arguments. + * Clean up the inactive streams when successful. + */ int snd_hda_codec_prepare(struct hda_codec *codec, struct hda_pcm_stream *hinfo, unsigned int stream, @@ -4687,6 +4799,14 @@ int snd_hda_codec_prepare(struct hda_codec *codec, } EXPORT_SYMBOL_GPL(snd_hda_codec_prepare); +/** + * snd_hda_codec_cleanup - Prepare a stream + * @codec: the HDA codec + * @hinfo: PCM information + * @substream: PCM substream + * + * Calls the cleanup callback set by the codec with the given arguments. + */ void snd_hda_codec_cleanup(struct hda_codec *codec, struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index b2d81ab22fb0..e664307617bd 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -20,6 +20,16 @@ #include "hda_auto_parser.h" #include "hda_jack.h" +/** + * is_jack_detectable - Check whether the given pin is jack-detectable + * @codec: the HDA codec + * @nid: pin NID + * + * Check whether the given pin is capable to report the jack detection. + * The jack detection might not work by various reasons, e.g. the jack + * detection is prohibited in the codec level, the pin config has + * AC_DEFCFG_MISC_NO_PRESENCE bit, no unsol support, etc. + */ bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid) { if (codec->no_jack_detect) @@ -268,6 +278,14 @@ snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, } EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable_callback); +/** + * snd_hda_jack_detect_enable - Enable the jack detection on the given pin + * @codec: the HDA codec + * @nid: pin NID to enable jack detection + * + * Enable the jack detection with the default callback. Returns zero if + * successful or a negative error code. + */ int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid) { return PTR_ERR_OR_ZERO(snd_hda_jack_detect_enable_callback(codec, nid, NULL)); @@ -410,6 +428,15 @@ static int __snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, return 0; } +/** + * snd_hda_jack_add_kctl - Add a jack kctl for the given pin + * @codec: the HDA codec + * @nid: pin NID + * @name: the name string for the jack ctl + * @idx: the ctl index for the jack ctl + * + * This is a simple helper calling __snd_hda_jack_add_kctl(). + */ int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, const char *name, int idx) { @@ -552,6 +579,11 @@ static void call_jack_callback(struct hda_codec *codec, } } +/** + * snd_hda_jack_unsol_event - Handle an unsolicited event + * @codec: the HDA codec + * @res: the unsolicited event data + */ void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res) { struct hda_jack_tbl *event; @@ -567,6 +599,13 @@ void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res) } EXPORT_SYMBOL_GPL(snd_hda_jack_unsol_event); +/** + * snd_hda_jack_poll_all - Poll all jacks + * @codec: the HDA codec + * + * Poll all detectable jacks with dirty flag, update the status, call + * callbacks and call snd_hda_jack_report_sync() if any changes are found. + */ void snd_hda_jack_poll_all(struct hda_codec *codec) { struct hda_jack_tbl *jack = codec->jacktbl.list; diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h index 13cb375454f6..b279e327a23b 100644 --- a/sound/pci/hda/hda_jack.h +++ b/sound/pci/hda/hda_jack.h @@ -72,6 +72,11 @@ enum { int snd_hda_jack_detect_state(struct hda_codec *codec, hda_nid_t nid); +/** + * snd_hda_jack_detect - Detect the jack + * @codec: the HDA codec + * @nid: pin NID to check jack detection + */ static inline bool snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid) { return snd_hda_jack_detect_state(codec, nid) != HDA_JACK_NOT_PRESENT; diff --git a/sound/pci/hda/hda_sysfs.c b/sound/pci/hda/hda_sysfs.c index 9b49f156a12e..bef721592c3a 100644 --- a/sound/pci/hda/hda_sysfs.c +++ b/sound/pci/hda/hda_sysfs.c @@ -417,8 +417,13 @@ static DEVICE_ATTR_RW(user_pin_configs); static DEVICE_ATTR_WO(reconfig); static DEVICE_ATTR_WO(clear); -/* - * Look for hint string +/** + * snd_hda_get_hint - Look for hint string + * @codec: the HDA codec + * @key: the hint key string + * + * Look for a hint key/value pair matching with the given key string + * and returns the value string. If nothing found, returns NULL. */ const char *snd_hda_get_hint(struct hda_codec *codec, const char *key) { @@ -427,6 +432,15 @@ const char *snd_hda_get_hint(struct hda_codec *codec, const char *key) } EXPORT_SYMBOL_GPL(snd_hda_get_hint); +/** + * snd_hda_get_bool_hint - Get a boolean hint value + * @codec: the HDA codec + * @key: the hint key string + * + * Look for a hint key/value pair matching with the given key string + * and returns a boolean value parsed from the value. If no matching + * key is found, return a negative value. + */ int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key) { const char *p; @@ -453,6 +467,16 @@ int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key) } EXPORT_SYMBOL_GPL(snd_hda_get_bool_hint); +/** + * snd_hda_get_bool_hint - Get a boolean hint value + * @codec: the HDA codec + * @key: the hint key string + * @valp: pointer to store a value + * + * Look for a hint key/value pair matching with the given key string + * and stores the integer value to @valp. If no matching key is found, + * return a negative error code. Otherwise it returns zero. + */ int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp) { const char *p; @@ -690,8 +714,11 @@ static int get_line_from_fw(char *buf, int size, size_t *fw_size_p, return 1; } -/* - * load a "patch" firmware file and parse it +/** + * snd_hda_load_patch - load a "patch" firmware file and parse it + * @bus: HD-audio bus + * @fw_size: the firmware byte size + * @fw_buf: the firmware data */ int snd_hda_load_patch(struct hda_bus *bus, size_t fw_size, const void *fw_buf) { -- cgit v1.2.3 From df57de172a47f16548ee4bb69d1110e32686d6a9 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Wed, 29 Oct 2014 20:09:45 +0530 Subject: ALSA: hdspm: remove unused variable removed the unused variables. These variables were only being assigned some value, but the values were never being used. it has been build tested after removing the variables. Signed-off-by: Sudip Mukherjee Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) (limited to 'sound') diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 7f7277bfb66a..e09348c156d8 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -1257,14 +1257,13 @@ static int hdspm_rate_multiplier(struct hdspm *hdspm, int rate) /* check for external sample rate, returns the sample rate in Hz*/ static int hdspm_external_sample_rate(struct hdspm *hdspm) { - unsigned int status, status2, timecode; + unsigned int status, status2; int syncref, rate = 0, rate_bits; switch (hdspm->io_type) { case AES32: status2 = hdspm_read(hdspm, HDSPM_statusRegister2); status = hdspm_read(hdspm, HDSPM_statusRegister); - timecode = hdspm_read(hdspm, HDSPM_timecodeRegister); syncref = hdspm_autosync_ref(hdspm); switch (syncref) { @@ -4862,18 +4861,15 @@ snd_hdspm_proc_read_madi(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct hdspm *hdspm = entry->private_data; - unsigned int status, status2, control, freq; + unsigned int status, status2; char *pref_sync_ref; char *autosync_ref; char *system_clock_mode; - char *insel; int x, x2; status = hdspm_read(hdspm, HDSPM_statusRegister); status2 = hdspm_read(hdspm, HDSPM_statusRegister2); - control = hdspm->control_register; - freq = hdspm_read(hdspm, HDSPM_timecodeRegister); snd_iprintf(buffer, "%s (Card #%d) Rev.%x Status2first3bits: %x\n", hdspm->card_name, hdspm->card->number + 1, @@ -4936,17 +4932,6 @@ snd_hdspm_proc_read_madi(struct snd_info_entry *entry, snd_iprintf(buffer, "Line out: %s\n", (hdspm->control_register & HDSPM_LineOut) ? "on " : "off"); - switch (hdspm->control_register & HDSPM_InputMask) { - case HDSPM_InputOptical: - insel = "Optical"; - break; - case HDSPM_InputCoaxial: - insel = "Coaxial"; - break; - default: - insel = "Unknown"; - } - snd_iprintf(buffer, "ClearTrackMarker = %s, Transmit in %s Channel Mode, " "Auto Input %s\n", @@ -5191,15 +5176,13 @@ snd_hdspm_proc_read_raydat(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct hdspm *hdspm = entry->private_data; - unsigned int status1, status2, status3, control, i; + unsigned int status1, status2, status3, i; unsigned int lock, sync; status1 = hdspm_read(hdspm, HDSPM_RD_STATUS_1); /* s1 */ status2 = hdspm_read(hdspm, HDSPM_RD_STATUS_2); /* freq */ status3 = hdspm_read(hdspm, HDSPM_RD_STATUS_3); /* s2 */ - control = hdspm->control_register; - snd_iprintf(buffer, "STATUS1: 0x%08x\n", status1); snd_iprintf(buffer, "STATUS2: 0x%08x\n", status2); snd_iprintf(buffer, "STATUS3: 0x%08x\n", status3); -- cgit v1.2.3 From eafe8404c103b3051b6421fc17e0e8b91d369f0b Mon Sep 17 00:00:00 2001 From: Tina Ruchandani Date: Wed, 29 Oct 2014 10:48:10 -0700 Subject: ALSA: es1968: Replace timeval with ktime_t es1968_measure_clock uses struct timeval, which on 32-bit systems will overflow in 2038, leading to incorrect interpretation of time.This patch changes the function to use ktime_t instead of struct timeval, which implies: - no y2038: ktime_t uses a 64-bit datatype explicitly. - efficent subtraction: The earlier version computes the difference in usecs while dealing with secs and nsecs. It requires checks to see if the nsecs of stop is less than start. This patch uses a direct subtract of ktime_t and converts to usecs. - use of monotonic clock (ktime_get) over real time (do_gettimeofday), which simplifies timekeeping, as it does not have to deal with cases where stop_time is less than start_time. Signed-off-by: Tina Ruchandani Reviewed-by: Arnd Bergmann Signed-off-by: Takashi Iwai --- sound/pci/es1968.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index a9956a7c5677..6039700f8579 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -1710,7 +1710,8 @@ static void es1968_measure_clock(struct es1968 *chip) int i, apu; unsigned int pa, offset, t; struct esm_memory *memory; - struct timeval start_time, stop_time; + ktime_t start_time, stop_time; + ktime_t diff; if (chip->clock == 0) chip->clock = 48000; /* default clock value */ @@ -1761,12 +1762,12 @@ static void es1968_measure_clock(struct es1968 *chip) snd_es1968_bob_inc(chip, ESM_BOB_FREQ); __apu_set_register(chip, apu, 5, pa & 0xffff); snd_es1968_trigger_apu(chip, apu, ESM_APU_16BITLINEAR); - do_gettimeofday(&start_time); + start_time = ktime_get(); spin_unlock_irq(&chip->reg_lock); msleep(50); spin_lock_irq(&chip->reg_lock); offset = __apu_get_register(chip, apu, 5); - do_gettimeofday(&stop_time); + stop_time = ktime_get(); snd_es1968_trigger_apu(chip, apu, 0); /* stop */ snd_es1968_bob_dec(chip); chip->in_measurement = 0; @@ -1777,12 +1778,8 @@ static void es1968_measure_clock(struct es1968 *chip) offset &= 0xfffe; offset += chip->measure_count * (CLOCK_MEASURE_BUFSIZE/2); - t = stop_time.tv_sec - start_time.tv_sec; - t *= 1000000; - if (stop_time.tv_usec < start_time.tv_usec) - t -= start_time.tv_usec - stop_time.tv_usec; - else - t += stop_time.tv_usec - start_time.tv_usec; + diff = ktime_sub(stop_time, start_time); + t = ktime_to_us(diff); if (t == 0) { dev_err(chip->card->dev, "?? calculation error..\n"); } else { -- cgit v1.2.3 From dda42bd0c3a4b7be1561546914eda59b68a58be4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 30 Oct 2014 12:04:50 +0100 Subject: ALSA: hda - Add kerneldoc comments to hda_generic.c Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_generic.c | 164 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 135 insertions(+), 29 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 06d721085e72..63b69f750d8e 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -40,7 +40,12 @@ #include "hda_generic.h" -/* initialize hda_gen_spec struct */ +/** + * snd_hda_gen_spec_init - initialize hda_gen_spec struct + * @spec: hda_gen_spec object to initialize + * + * Initialize the given hda_gen_spec object. + */ int snd_hda_gen_spec_init(struct hda_gen_spec *spec) { snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32); @@ -51,6 +56,17 @@ int snd_hda_gen_spec_init(struct hda_gen_spec *spec) } EXPORT_SYMBOL_GPL(snd_hda_gen_spec_init); +/** + * snd_hda_gen_add_kctl - Add a new kctl_new struct from the template + * @spec: hda_gen_spec object + * @name: name string to override the template, NULL if unchanged + * @temp: template for the new kctl + * + * Add a new kctl (actually snd_kcontrol_new to be instantiated later) + * element based on the given snd_kcontrol_new template @temp and the + * name string @name to the list in @spec. + * Returns the newly created object or NULL as error. + */ struct snd_kcontrol_new * snd_hda_gen_add_kctl(struct hda_gen_spec *spec, const char *name, const struct snd_kcontrol_new *temp) @@ -259,8 +275,14 @@ static struct nid_path *get_nid_path(struct hda_codec *codec, return NULL; } -/* get the path between the given NIDs; - * passing 0 to either @pin or @dac behaves as a wildcard +/** + * snd_hda_get_nid_path - get the path between the given NIDs + * @codec: the HDA codec + * @from_nid: the NID where the path start from + * @to_nid: the NID where the path ends at + * + * Return the found nid_path object or NULL for error. + * Passing 0 to either @from_nid or @to_nid behaves as a wildcard. */ struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec, hda_nid_t from_nid, hda_nid_t to_nid) @@ -269,8 +291,14 @@ struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec, } EXPORT_SYMBOL_GPL(snd_hda_get_nid_path); -/* get the index number corresponding to the path instance; - * the index starts from 1, for easier checking the invalid value +/** + * snd_hda_get_path_idx - get the index number corresponding to the path + * instance + * @codec: the HDA codec + * @path: nid_path object + * + * The returned index starts from 1, i.e. the actual array index with offset 1, + * and zero is handled as an invalid path */ int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path) { @@ -287,7 +315,12 @@ int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path) } EXPORT_SYMBOL_GPL(snd_hda_get_path_idx); -/* get the path instance corresponding to the given index number */ +/** + * snd_hda_get_path_from_idx - get the path instance corresponding to the + * given index number + * @codec: the HDA codec + * @idx: the path index + */ struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx) { struct hda_gen_spec *spec = codec->spec; @@ -415,7 +448,18 @@ static bool __parse_nid_path(struct hda_codec *codec, return true; } -/* parse the widget path from the given nid to the target nid; +/** + * snd_hda_parse_nid_path - parse the widget path from the given nid to + * the target nid + * @codec: the HDA codec + * @from_nid: the NID where the path start from + * @to_nid: the NID where the path ends at + * @anchor_nid: the anchor indication + * @path: the path object to store the result + * + * Returns true if a matching path is found. + * + * The parsing behavior depends on parameters: * when @from_nid is 0, try to find an empty DAC; * when @anchor_nid is set to a positive value, only paths through the widget * with the given value are evaluated. @@ -436,9 +480,15 @@ bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid, } EXPORT_SYMBOL_GPL(snd_hda_parse_nid_path); -/* - * parse the path between the given NIDs and add to the path list. - * if no valid path is found, return NULL +/** + * snd_hda_add_new_path - parse the path between the given NIDs and + * add to the path list + * @codec: the HDA codec + * @from_nid: the NID where the path start from + * @to_nid: the NID where the path ends at + * @anchor_nid: the anchor indication, see snd_hda_parse_nid_path() + * + * If no valid path is found, returns NULL. */ struct nid_path * snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid, @@ -724,8 +774,14 @@ static void activate_amp_in(struct hda_codec *codec, struct nid_path *path, } } -/* activate or deactivate the given path - * if @add_aamix is set, enable the input from aa-mix NID as well (if any) +/** + * snd_hda_activate_path - activate or deactivate the given path + * @codec: the HDA codec + * @path: the path to activate/deactivate + * @enable: flag to activate or not + * @add_aamix: enable the input from aamix NID + * + * If @add_aamix is set, enable the input from aa-mix NID as well (if any). */ void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path, bool enable, bool add_aamix) @@ -3883,7 +3939,12 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, } } -/* Toggle outputs muting */ +/** + * snd_hda_gen_update_outputs - Toggle outputs muting + * @codec: the HDA codec + * + * Update the mute status of all outputs based on the current jack states. + */ void snd_hda_gen_update_outputs(struct hda_codec *codec) { struct hda_gen_spec *spec = codec->spec; @@ -3944,7 +4005,11 @@ static void call_update_outputs(struct hda_codec *codec) snd_ctl_sync_vmaster(spec->vmaster_mute.sw_kctl, false); } -/* standard HP-automute helper */ +/** + * snd_hda_gen_hp_automute - standard HP-automute helper + * @codec: the HDA codec + * @jack: jack object, NULL for the whole + */ void snd_hda_gen_hp_automute(struct hda_codec *codec, struct hda_jack_callback *jack) { @@ -3965,7 +4030,11 @@ void snd_hda_gen_hp_automute(struct hda_codec *codec, } EXPORT_SYMBOL_GPL(snd_hda_gen_hp_automute); -/* standard line-out-automute helper */ +/** + * snd_hda_gen_line_automute - standard line-out-automute helper + * @codec: the HDA codec + * @jack: jack object, NULL for the whole + */ void snd_hda_gen_line_automute(struct hda_codec *codec, struct hda_jack_callback *jack) { @@ -3986,7 +4055,11 @@ void snd_hda_gen_line_automute(struct hda_codec *codec, } EXPORT_SYMBOL_GPL(snd_hda_gen_line_automute); -/* standard mic auto-switch helper */ +/** + * snd_hda_gen_mic_autoswitch - standard mic auto-switch helper + * @codec: the HDA codec + * @jack: jack object, NULL for the whole + */ void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, struct hda_jack_callback *jack) { @@ -4318,7 +4391,13 @@ static int check_auto_mic_availability(struct hda_codec *codec) return 0; } -/* power_filter hook; make inactive widgets into power down */ +/** + * snd_hda_gen_path_power_filter - power_filter hook to make inactive widgets + * into power down + * @codec: the HDA codec + * @nid: NID to evalute + * @power_state: target power state + */ unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec, hda_nid_t nid, unsigned int power_state) @@ -4354,8 +4433,11 @@ static void mute_all_mixer_nid(struct hda_codec *codec, hda_nid_t mix) } } -/* - * Parse the given BIOS configuration and set up the hda_gen_spec +/** + * snd_hda_gen_parse_auto_config - Parse the given BIOS configuration and + * set up the hda_gen_spec + * @codec: the HDA codec + * @cfg: Parsed pin configuration * * return 1 if successful, 0 if the proper config is not found, * or a negative error code @@ -4541,6 +4623,12 @@ static const char * const slave_pfxs[] = { NULL, }; +/** + * snd_hda_gen_build_controls - Build controls from the parsed results + * @codec: the HDA codec + * + * Pass this to build_controls patch_ops. + */ int snd_hda_gen_build_controls(struct hda_codec *codec) { struct hda_gen_spec *spec = codec->spec; @@ -5018,7 +5106,12 @@ static void fill_pcm_stream_name(char *str, size_t len, const char *sfx, strlcat(str, sfx, len); } -/* build PCM streams based on the parsed results */ +/** + * snd_hda_gen_build_pcms - build PCM streams based on the parsed results + * @codec: the HDA codec + * + * Pass this to build_pcms patch_ops. + */ int snd_hda_gen_build_pcms(struct hda_codec *codec) { struct hda_gen_spec *spec = codec->spec; @@ -5313,9 +5406,11 @@ static void clear_unsol_on_unused_pins(struct hda_codec *codec) } } -/* - * initialize the generic spec; - * this can be put as patch_ops.init function +/** + * snd_hda_gen_init - initialize the generic spec + * @codec: the HDA codec + * + * This can be put as patch_ops init function. */ int snd_hda_gen_init(struct hda_codec *codec) { @@ -5351,9 +5446,11 @@ int snd_hda_gen_init(struct hda_codec *codec) } EXPORT_SYMBOL_GPL(snd_hda_gen_init); -/* - * free the generic spec; - * this can be put as patch_ops.free function +/** + * snd_hda_gen_free - free the generic spec + * @codec: the HDA codec + * + * This can be put as patch_ops free function. */ void snd_hda_gen_free(struct hda_codec *codec) { @@ -5365,9 +5462,12 @@ void snd_hda_gen_free(struct hda_codec *codec) EXPORT_SYMBOL_GPL(snd_hda_gen_free); #ifdef CONFIG_PM -/* - * check the loopback power save state; - * this can be put as patch_ops.check_power_status function +/** + * snd_hda_gen_check_power_status - check the loopback power save state + * @codec: the HDA codec + * @nid: NID to inspect + * + * This can be put as patch_ops check_power_status function. */ int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid) { @@ -5393,6 +5493,12 @@ static const struct hda_codec_ops generic_patch_ops = { #endif }; +/** + * snd_hda_parse_generic_codec - Generic codec parser + * @codec: the HDA codec + * + * This should be called from the HDA codec core. + */ int snd_hda_parse_generic_codec(struct hda_codec *codec) { struct hda_gen_spec *spec; -- cgit v1.2.3 From 12cddbd8696657ff405e054be48747b906731698 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 30 Oct 2014 13:44:34 +0100 Subject: ALSA: control: Add missing kerneldoc comments to exported functions A few functions have no proper documentation yet, so let's add them. Along with it, remove superfluous blank line between the closing brace and EXPORT_SYMBOL() line. Signed-off-by: Takashi Iwai --- sound/core/control.c | 64 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 49 insertions(+), 15 deletions(-) (limited to 'sound') diff --git a/sound/core/control.c b/sound/core/control.c index 5c35bbaf881e..99aa3aa157ba 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -141,6 +141,16 @@ static int snd_ctl_release(struct inode *inode, struct file *file) return 0; } +/** + * snd_ctl_notify - Send notification to user-space for a control change + * @card: the card to send notification + * @mask: the event mask, SNDRV_CTL_EVENT_* + * @id: the ctl element id to send notification + * + * This function adds an event record with the given id and mask, appends + * to the list and wakes up the user-space for notification. This can be + * called in the atomic context. + */ void snd_ctl_notify(struct snd_card *card, unsigned int mask, struct snd_ctl_elem_id *id) { @@ -179,7 +189,6 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask, } read_unlock(&card->ctl_files_rwlock); } - EXPORT_SYMBOL(snd_ctl_notify); /** @@ -261,7 +270,6 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol, kctl.private_data = private_data; return snd_ctl_new(&kctl, access); } - EXPORT_SYMBOL(snd_ctl_new1); /** @@ -280,7 +288,6 @@ void snd_ctl_free_one(struct snd_kcontrol *kcontrol) kfree(kcontrol); } } - EXPORT_SYMBOL(snd_ctl_free_one); static bool snd_ctl_remove_numid_conflict(struct snd_card *card, @@ -376,7 +383,6 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) snd_ctl_free_one(kcontrol); return err; } - EXPORT_SYMBOL(snd_ctl_add); /** @@ -471,7 +477,6 @@ int snd_ctl_remove(struct snd_card *card, struct snd_kcontrol *kcontrol) snd_ctl_free_one(kcontrol); return 0; } - EXPORT_SYMBOL(snd_ctl_remove); /** @@ -499,7 +504,6 @@ int snd_ctl_remove_id(struct snd_card *card, struct snd_ctl_elem_id *id) up_write(&card->controls_rwsem); return ret; } - EXPORT_SYMBOL(snd_ctl_remove_id); /** @@ -617,7 +621,6 @@ int snd_ctl_rename_id(struct snd_card *card, struct snd_ctl_elem_id *src_id, up_write(&card->controls_rwsem); return 0; } - EXPORT_SYMBOL(snd_ctl_rename_id); /** @@ -645,7 +648,6 @@ struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numi } return NULL; } - EXPORT_SYMBOL(snd_ctl_find_numid); /** @@ -687,7 +689,6 @@ struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card, } return NULL; } - EXPORT_SYMBOL(snd_ctl_find_id); static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl, @@ -1526,19 +1527,28 @@ static int _snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn, struct list_head * return 0; } +/** + * snd_ctl_register_ioctl - register the device-specific control-ioctls + * @fcn: ioctl callback function + * + * called from each device manager like pcm.c, hwdep.c, etc. + */ int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn) { return _snd_ctl_register_ioctl(fcn, &snd_control_ioctls); } - EXPORT_SYMBOL(snd_ctl_register_ioctl); #ifdef CONFIG_COMPAT +/** + * snd_ctl_register_ioctl_compat - register the device-specific 32bit compat + * control-ioctls + * @fcn: ioctl callback function + */ int snd_ctl_register_ioctl_compat(snd_kctl_ioctl_func_t fcn) { return _snd_ctl_register_ioctl(fcn, &snd_control_compat_ioctls); } - EXPORT_SYMBOL(snd_ctl_register_ioctl_compat); #endif @@ -1566,19 +1576,26 @@ static int _snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn, return -EINVAL; } +/** + * snd_ctl_unregister_ioctl - de-register the device-specific control-ioctls + * @fcn: ioctl callback function to unregister + */ int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn) { return _snd_ctl_unregister_ioctl(fcn, &snd_control_ioctls); } - EXPORT_SYMBOL(snd_ctl_unregister_ioctl); #ifdef CONFIG_COMPAT +/** + * snd_ctl_unregister_ioctl - de-register the device-specific compat 32bit + * control-ioctls + * @fcn: ioctl callback function to unregister + */ int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn) { return _snd_ctl_unregister_ioctl(fcn, &snd_control_compat_ioctls); } - EXPORT_SYMBOL(snd_ctl_unregister_ioctl_compat); #endif @@ -1702,6 +1719,16 @@ int snd_ctl_create(struct snd_card *card) /* * Frequently used control callbacks/helpers */ + +/** + * snd_ctl_boolean_mono_info - Helper function for a standard boolean info + * callback with a mono channel + * @kcontrol: the kcontrol instance + * @uinfo: info to store + * + * This is a function that can be used as info callback for a standard + * boolean control with a single mono channel. + */ int snd_ctl_boolean_mono_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -1711,9 +1738,17 @@ int snd_ctl_boolean_mono_info(struct snd_kcontrol *kcontrol, uinfo->value.integer.max = 1; return 0; } - EXPORT_SYMBOL(snd_ctl_boolean_mono_info); +/** + * snd_ctl_boolean_stereo_info - Helper function for a standard boolean info + * callback with stereo two channels + * @kcontrol: the kcontrol instance + * @uinfo: info to store + * + * This is a function that can be used as info callback for a standard + * boolean control with stereo two channels. + */ int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -1723,7 +1758,6 @@ int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol, uinfo->value.integer.max = 1; return 0; } - EXPORT_SYMBOL(snd_ctl_boolean_stereo_info); /** -- cgit v1.2.3 From 30b771cf8c3120c5c946811ecc5a9b87a34003a2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 30 Oct 2014 15:02:50 +0100 Subject: ALSA: pcm: More kerneldoc updates Add proper kerneldoc comments to the exported functions. Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 160 +++++++++++++++++++++++++++++++++++++++++++++--- sound/core/pcm.c | 15 ++++- sound/core/pcm_native.c | 53 ++++++++++++++++ 3 files changed, 219 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 5c3310d7d4b8..f78a5722f5cc 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -533,6 +533,12 @@ snd_pcm_debug_name(struct snd_pcm_substream *substream, char *buf, size_t size) * PCM library */ +/** + * snd_pcm_stream_linked - Check whether the substream is linked with others + * @substream: substream to check + * + * Returns true if the given substream is being linked with others. + */ static inline int snd_pcm_stream_linked(struct snd_pcm_substream *substream) { return substream->group != &substream->self_group; @@ -543,6 +549,16 @@ void snd_pcm_stream_unlock(struct snd_pcm_substream *substream); void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream); void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream); unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream); + +/** + * snd_pcm_stream_lock_irqsave - Lock the PCM stream + * @substream: PCM substream + * @flags: irq flags + * + * This locks the PCM stream like snd_pcm_stream_lock() but with the local + * IRQ (only when nonatomic is false). In nonatomic case, this is identical + * as snd_pcm_stream_lock(). + */ #define snd_pcm_stream_lock_irqsave(substream, flags) \ do { \ typecheck(unsigned long, flags); \ @@ -551,9 +567,25 @@ unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream); void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream, unsigned long flags); +/** + * snd_pcm_group_for_each_entry - iterate over the linked substreams + * @s: the iterator + * @substream: the substream + * + * Iterate over the all linked substreams to the given @substream. + * When @substream isn't linked with any others, this gives returns @substream + * itself once. + */ #define snd_pcm_group_for_each_entry(s, substream) \ list_for_each_entry(s, &substream->group->substreams, link_list) +/** + * snd_pcm_running - Check whether the substream is in a running state + * @substream: substream to check + * + * Returns true if the given substream is in the state RUNNING, or in the + * state DRAINING for playback. + */ static inline int snd_pcm_running(struct snd_pcm_substream *substream) { return (substream->runtime->status->state == SNDRV_PCM_STATE_RUNNING || @@ -561,45 +593,81 @@ static inline int snd_pcm_running(struct snd_pcm_substream *substream) substream->stream == SNDRV_PCM_STREAM_PLAYBACK)); } +/** + * bytes_to_samples - Unit conversion of the size from bytes to samples + * @runtime: PCM runtime instance + * @size: size in bytes + */ static inline ssize_t bytes_to_samples(struct snd_pcm_runtime *runtime, ssize_t size) { return size * 8 / runtime->sample_bits; } +/** + * bytes_to_frames - Unit conversion of the size from bytes to frames + * @runtime: PCM runtime instance + * @size: size in bytes + */ static inline snd_pcm_sframes_t bytes_to_frames(struct snd_pcm_runtime *runtime, ssize_t size) { return size * 8 / runtime->frame_bits; } +/** + * samples_to_bytes - Unit conversion of the size from samples to bytes + * @runtime: PCM runtime instance + * @size: size in samples + */ static inline ssize_t samples_to_bytes(struct snd_pcm_runtime *runtime, ssize_t size) { return size * runtime->sample_bits / 8; } +/** + * frames_to_bytes - Unit conversion of the size from frames to bytes + * @runtime: PCM runtime instance + * @size: size in frames + */ static inline ssize_t frames_to_bytes(struct snd_pcm_runtime *runtime, snd_pcm_sframes_t size) { return size * runtime->frame_bits / 8; } +/** + * frame_aligned - Check whether the byte size is aligned to frames + * @runtime: PCM runtime instance + * @bytes: size in bytes + */ static inline int frame_aligned(struct snd_pcm_runtime *runtime, ssize_t bytes) { return bytes % runtime->byte_align == 0; } +/** + * snd_pcm_lib_buffer_bytes - Get the buffer size of the current PCM in bytes + * @substream: PCM substream + */ static inline size_t snd_pcm_lib_buffer_bytes(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; return frames_to_bytes(runtime, runtime->buffer_size); } +/** + * snd_pcm_lib_period_bytes - Get the period size of the current PCM in bytes + * @substream: PCM substream + */ static inline size_t snd_pcm_lib_period_bytes(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; return frames_to_bytes(runtime, runtime->period_size); } -/* - * result is: 0 ... (boundary - 1) +/** + * snd_pcm_playback_avail - Get the available (writable) space for playback + * @runtime: PCM runtime instance + * + * Result is between 0 ... (boundary - 1) */ static inline snd_pcm_uframes_t snd_pcm_playback_avail(struct snd_pcm_runtime *runtime) { @@ -611,8 +679,11 @@ static inline snd_pcm_uframes_t snd_pcm_playback_avail(struct snd_pcm_runtime *r return avail; } -/* - * result is: 0 ... (boundary - 1) +/** + * snd_pcm_playback_avail - Get the available (readable) space for capture + * @runtime: PCM runtime instance + * + * Result is between 0 ... (boundary - 1) */ static inline snd_pcm_uframes_t snd_pcm_capture_avail(struct snd_pcm_runtime *runtime) { @@ -622,11 +693,19 @@ static inline snd_pcm_uframes_t snd_pcm_capture_avail(struct snd_pcm_runtime *ru return avail; } +/** + * snd_pcm_playback_hw_avail - Get the queued space for playback + * @runtime: PCM runtime instance + */ static inline snd_pcm_sframes_t snd_pcm_playback_hw_avail(struct snd_pcm_runtime *runtime) { return runtime->buffer_size - snd_pcm_playback_avail(runtime); } +/** + * snd_pcm_capture_hw_avail - Get the free space for capture + * @runtime: PCM runtime instance + */ static inline snd_pcm_sframes_t snd_pcm_capture_hw_avail(struct snd_pcm_runtime *runtime) { return runtime->buffer_size - snd_pcm_capture_avail(runtime); @@ -706,6 +785,20 @@ static inline int snd_pcm_capture_empty(struct snd_pcm_substream *substream) return snd_pcm_capture_avail(runtime) == 0; } +/** + * snd_pcm_trigger_done - Mark the master substream + * @substream: the pcm substream instance + * @master: the linked master substream + * + * When multiple substreams of the same card are linked and the hardware + * supports the single-shot operation, the driver calls this in the loop + * in snd_pcm_group_for_each_entry() for marking the substream as "done". + * Then most of trigger operations are performed only to the given master + * substream. + * + * The trigger_master mark is cleared at timestamp updates at the end + * of trigger operations. + */ static inline void snd_pcm_trigger_done(struct snd_pcm_substream *substream, struct snd_pcm_substream *master) { @@ -881,6 +974,14 @@ unsigned int snd_pcm_rate_bit_to_rate(unsigned int rate_bit); unsigned int snd_pcm_rate_mask_intersect(unsigned int rates_a, unsigned int rates_b); +/** + * snd_pcm_set_runtime_buffer - Set the PCM runtime buffer + * @substream: PCM substream to set + * @bufp: the buffer information, NULL to clear + * + * Copy the buffer information to runtime->dma_buffer when @bufp is non-NULL. + * Otherwise it clears the current buffer information. + */ static inline void snd_pcm_set_runtime_buffer(struct snd_pcm_substream *substream, struct snd_dma_buffer *bufp) { @@ -906,6 +1007,11 @@ void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream); void snd_pcm_timer_init(struct snd_pcm_substream *substream); void snd_pcm_timer_done(struct snd_pcm_substream *substream); +/** + * snd_pcm_gettime - Fill the timespec depending on the timestamp mode + * @runtime: PCM runtime instance + * @tv: timespec to fill + */ static inline void snd_pcm_gettime(struct snd_pcm_runtime *runtime, struct timespec *tv) { @@ -997,18 +1103,35 @@ struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, #define snd_pcm_sgbuf_ops_page NULL #endif /* SND_DMA_SGBUF */ +/** + * snd_pcm_sgbuf_get_addr - Get the DMA address at the corresponding offset + * @substream: PCM substream + * @ofs: byte offset + */ static inline dma_addr_t snd_pcm_sgbuf_get_addr(struct snd_pcm_substream *substream, unsigned int ofs) { return snd_sgbuf_get_addr(snd_pcm_get_dma_buf(substream), ofs); } +/** + * snd_pcm_sgbuf_get_ptr - Get the virtual address at the corresponding offset + * @substream: PCM substream + * @ofs: byte offset + */ static inline void * snd_pcm_sgbuf_get_ptr(struct snd_pcm_substream *substream, unsigned int ofs) { return snd_sgbuf_get_ptr(snd_pcm_get_dma_buf(substream), ofs); } +/** + * snd_pcm_sgbuf_chunk_size - Compute the max size that fits within the contig. + * page from the given size + * @substream: PCM substream + * @ofs: byte offset + * @size: byte size to examine + */ static inline unsigned int snd_pcm_sgbuf_get_chunk_size(struct snd_pcm_substream *substream, unsigned int ofs, unsigned int size) @@ -1016,13 +1139,24 @@ snd_pcm_sgbuf_get_chunk_size(struct snd_pcm_substream *substream, return snd_sgbuf_get_chunk_size(snd_pcm_get_dma_buf(substream), ofs, size); } -/* handle mmap counter - PCM mmap callback should handle this counter properly */ +/** + * snd_pcm_mmap_data_open - increase the mmap counter + * @area: VMA + * + * PCM mmap callback should handle this counter properly + */ static inline void snd_pcm_mmap_data_open(struct vm_area_struct *area) { struct snd_pcm_substream *substream = (struct snd_pcm_substream *)area->vm_private_data; atomic_inc(&substream->mmap_count); } +/** + * snd_pcm_mmap_data_close - decrease the mmap counter + * @area: VMA + * + * PCM mmap callback should handle this counter properly + */ static inline void snd_pcm_mmap_data_close(struct vm_area_struct *area) { struct snd_pcm_substream *substream = (struct snd_pcm_substream *)area->vm_private_data; @@ -1042,6 +1176,11 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, struct vm_area_s #define snd_pcm_lib_mmap_vmalloc NULL +/** + * snd_pcm_limit_isa_dma_size - Get the max size fitting with ISA DMA transfer + * @dma: DMA number + * @max: pointer to store the max size + */ static inline void snd_pcm_limit_isa_dma_size(int dma, size_t *max) { *max = dma < 4 ? 64 * 1024 : 128 * 1024; @@ -1094,7 +1233,11 @@ struct snd_pcm_chmap { void *private_data; /* optional: private data pointer */ }; -/* get the PCM substream assigned to the given chmap info */ +/** + * snd_pcm_chmap_substream - get the PCM substream assigned to the given chmap info + * @info: chmap information + * @idx: the substream number index + */ static inline struct snd_pcm_substream * snd_pcm_chmap_substream(struct snd_pcm_chmap *info, unsigned int idx) { @@ -1121,7 +1264,10 @@ int snd_pcm_add_chmap_ctls(struct snd_pcm *pcm, int stream, unsigned long private_value, struct snd_pcm_chmap **info_ret); -/* Strong-typed conversion of pcm_format to bitwise */ +/** + * pcm_format_to_bits - Strong-typed conversion of pcm_format to bitwise + * @pcm_format: PCM format + */ static inline u64 pcm_format_to_bits(snd_pcm_format_t pcm_format) { return 1ULL << (__force int) pcm_format; diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 42ded997b223..31acc3df62cd 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -218,6 +218,10 @@ static char *snd_pcm_format_names[] = { FORMAT(DSD_U32_LE), }; +/** + * snd_pcm_format_name - Return a name string for the given PCM format + * @format: PCM format + */ const char *snd_pcm_format_name(snd_pcm_format_t format) { if ((__force unsigned int)format >= ARRAY_SIZE(snd_pcm_format_names)) @@ -707,7 +711,6 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count) } return 0; } - EXPORT_SYMBOL(snd_pcm_new_stream); static int _snd_pcm_new(struct snd_card *card, const char *id, int device, @@ -1155,6 +1158,15 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) return 0; } +/** + * snd_pcm_notify - Add/remove the notify list + * @notify: PCM notify list + * @nfree: 0 = register, 1 = unregister + * + * This adds the given notifier to the global list so that the callback is + * called for each registered PCM devices. This exists only for PCM OSS + * emulation, so far. + */ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree) { struct snd_pcm *pcm; @@ -1177,7 +1189,6 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree) mutex_unlock(®ister_mutex); return 0; } - EXPORT_SYMBOL(snd_pcm_notify); #ifdef CONFIG_PROC_FS diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 2f7ad10ee7c3..4d5795d8b9f7 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -74,6 +74,14 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream); static DEFINE_RWLOCK(snd_pcm_link_rwlock); static DECLARE_RWSEM(snd_pcm_link_rwsem); +/** + * snd_pcm_stream_lock - Lock the PCM stream + * @substream: PCM substream + * + * This locks the PCM stream's spinlock or mutex depending on the nonatomic + * flag of the given substream. This also takes the global link rw lock + * (or rw sem), too, for avoiding the race with linked streams. + */ void snd_pcm_stream_lock(struct snd_pcm_substream *substream) { if (substream->pcm->nonatomic) { @@ -86,6 +94,12 @@ void snd_pcm_stream_lock(struct snd_pcm_substream *substream) } EXPORT_SYMBOL_GPL(snd_pcm_stream_lock); +/** + * snd_pcm_stream_lock - Unlock the PCM stream + * @substream: PCM substream + * + * This unlocks the PCM stream that has been locked via snd_pcm_stream_lock(). + */ void snd_pcm_stream_unlock(struct snd_pcm_substream *substream) { if (substream->pcm->nonatomic) { @@ -98,6 +112,14 @@ void snd_pcm_stream_unlock(struct snd_pcm_substream *substream) } EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock); +/** + * snd_pcm_stream_lock_irq - Lock the PCM stream + * @substream: PCM substream + * + * This locks the PCM stream like snd_pcm_stream_lock() and disables the local + * IRQ (only when nonatomic is false). In nonatomic case, this is identical + * as snd_pcm_stream_lock(). + */ void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream) { if (!substream->pcm->nonatomic) @@ -106,6 +128,12 @@ void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream) } EXPORT_SYMBOL_GPL(snd_pcm_stream_lock_irq); +/** + * snd_pcm_stream_unlock_irq - Unlock the PCM stream + * @substream: PCM substream + * + * This is a counter-part of snd_pcm_stream_lock_irq(). + */ void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream) { snd_pcm_stream_unlock(substream); @@ -124,6 +152,13 @@ unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream) } EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave); +/** + * snd_pcm_stream_unlock_irqrestore - Unlock the PCM stream + * @substream: PCM substream + * @flags: irq flags + * + * This is a counter-part of snd_pcm_stream_lock_irqsave(). + */ void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream, unsigned long flags) { @@ -3312,6 +3347,15 @@ static const struct vm_operations_struct snd_pcm_vm_ops_data_fault = { /* * mmap the DMA buffer on RAM */ + +/** + * snd_pcm_lib_default_mmap - Default PCM data mmap function + * @substream: PCM substream + * @area: VMA + * + * This is the default mmap handler for PCM data. When mmap pcm_ops is NULL, + * this function is invoked implicitly. + */ int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *area) { @@ -3343,6 +3387,15 @@ EXPORT_SYMBOL_GPL(snd_pcm_lib_default_mmap); * mmap the DMA buffer on I/O memory area */ #if SNDRV_PCM_INFO_MMAP_IOMEM +/** + * snd_pcm_lib_mmap_iomem - Default PCM data mmap function for I/O mem + * @substream: PCM substream + * @area: VMA + * + * When your hardware uses the iomapped pages as the hardware buffer and + * wants to mmap it, pass this function as mmap pcm_ops. Note that this + * is supposed to work only on limited architectures. + */ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, struct vm_area_struct *area) { -- cgit v1.2.3 From eb9c38d54c9cad72101dfe7fefe4a784dd67da86 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 30 Oct 2014 15:19:43 +0100 Subject: ALSA: doc: More kerneldoc comments on core components Some functions missed the proper kerneldoc comments. Signed-off-by: Takashi Iwai --- sound/core/init.c | 33 ++++++++++++++++++++++----------- sound/core/sound.c | 9 +++++++-- 2 files changed, 29 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/core/init.c b/sound/core/init.c index 7bdfd19e24a8..074875d68c15 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -438,17 +438,6 @@ int snd_card_disconnect(struct snd_card *card) EXPORT_SYMBOL(snd_card_disconnect); -/** - * snd_card_free - frees given soundcard structure - * @card: soundcard structure - * - * This function releases the soundcard structure and the all assigned - * devices automatically. That is, you don't have to release the devices - * by yourself. - * - * Return: Zero. Frees all associated devices and frees the control - * interface associated to given soundcard. - */ static int snd_card_do_free(struct snd_card *card) { #if IS_ENABLED(CONFIG_SND_MIXER_OSS) @@ -469,6 +458,15 @@ static int snd_card_do_free(struct snd_card *card) return 0; } +/** + * snd_card_free_when_closed - Disconnect the card, free it later eventually + * @card: soundcard structure + * + * Unlike snd_card_free(), this function doesn't try to release the card + * resource immediately, but tries to disconnect at first. When the card + * is still in use, the function returns before freeing the resources. + * The card resources will be freed when the refcount gets to zero. + */ int snd_card_free_when_closed(struct snd_card *card) { int ret = snd_card_disconnect(card); @@ -479,6 +477,19 @@ int snd_card_free_when_closed(struct snd_card *card) } EXPORT_SYMBOL(snd_card_free_when_closed); +/** + * snd_card_free - frees given soundcard structure + * @card: soundcard structure + * + * This function releases the soundcard structure and the all assigned + * devices automatically. That is, you don't have to release the devices + * by yourself. + * + * This function waits until the all resources are properly released. + * + * Return: Zero. Frees all associated devices and frees the control + * interface associated to given soundcard. + */ int snd_card_free(struct snd_card *card) { struct completion released; diff --git a/sound/core/sound.c b/sound/core/sound.c index 38ad1a0dd3f7..f1333060bf1c 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -355,8 +355,13 @@ int snd_unregister_device(int type, struct snd_card *card, int dev) EXPORT_SYMBOL(snd_unregister_device); -/* get the assigned device to the given type and device number; - * the caller needs to release it via put_device() after using it +/** + * snd_get_device - get the assigned device to the given type and device number + * @type: the device type, SNDRV_DEVICE_TYPE_XXX + * @card:the card instance + * @dev: the device index + * + * The caller needs to release it via put_device() after using it. */ struct device *snd_get_device(int type, struct snd_card *card, int dev) { -- cgit v1.2.3 From e3a4bd5eec52912108e287146052f2624acbec7a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 31 Oct 2014 14:45:04 +0100 Subject: ALSA: pcm: Simplify snd_pcm_action_lock_irq() The function snd_pcm_action_lock_irq() can be much simplified by simply wrapping snd_pcm_action() with the stream lock. This was rather the original idea, but later it was open coded for optimization. However, looking at the optimization part closely, one notices that the probability of the optimized path is quite low; in normal situations, the linked stream action happens only for the triggered substream, thus the operation becomes identical. So the code simplification has a clear win, especially because we have now doubly codes for both atomic and non-atomic locks. Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 41 +++-------------------------------------- 1 file changed, 3 insertions(+), 38 deletions(-) (limited to 'sound') diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 4d5795d8b9f7..b92b605fc784 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -947,28 +947,6 @@ static int snd_pcm_action(struct action_ops *ops, return res; } -static int snd_pcm_action_lock_mutex(struct action_ops *ops, - struct snd_pcm_substream *substream, - int state) -{ - int res; - - down_read(&snd_pcm_link_rwsem); - if (snd_pcm_stream_linked(substream)) { - mutex_lock(&substream->group->mutex); - mutex_lock(&substream->self_group.mutex); - res = snd_pcm_action_group(ops, substream, state, 1); - mutex_unlock(&substream->self_group.mutex); - mutex_unlock(&substream->group->mutex); - } else { - mutex_lock(&substream->self_group.mutex); - res = snd_pcm_action_single(ops, substream, state); - mutex_unlock(&substream->self_group.mutex); - } - up_read(&snd_pcm_link_rwsem); - return res; -} - /* * Note: don't use any locks before */ @@ -978,22 +956,9 @@ static int snd_pcm_action_lock_irq(struct action_ops *ops, { int res; - if (substream->pcm->nonatomic) - return snd_pcm_action_lock_mutex(ops, substream, state); - - read_lock_irq(&snd_pcm_link_rwlock); - if (snd_pcm_stream_linked(substream)) { - spin_lock(&substream->group->lock); - spin_lock(&substream->self_group.lock); - res = snd_pcm_action_group(ops, substream, state, 1); - spin_unlock(&substream->self_group.lock); - spin_unlock(&substream->group->lock); - } else { - spin_lock(&substream->self_group.lock); - res = snd_pcm_action_single(ops, substream, state); - spin_unlock(&substream->self_group.lock); - } - read_unlock_irq(&snd_pcm_link_rwlock); + snd_pcm_stream_lock_irq(substream); + res = snd_pcm_action(ops, substream, state); + snd_pcm_stream_unlock_irq(substream); return res; } -- cgit v1.2.3 From aa8edd8ca6a110349b00e360823c64e8cd106289 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 31 Oct 2014 15:19:36 +0100 Subject: ALSA: pcm: Refactoring snd_pcm_action() Just a small code refactoring to reduce more lines. Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 35 ++++++++++------------------------- 1 file changed, 10 insertions(+), 25 deletions(-) (limited to 'sound') diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index b92b605fc784..ca224fa2a33a 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -900,14 +900,19 @@ static int snd_pcm_action_single(struct action_ops *ops, return res; } -/* call in mutex-protected context */ -static int snd_pcm_action_mutex(struct action_ops *ops, - struct snd_pcm_substream *substream, - int state) +/* + * Note: call with stream lock + */ +static int snd_pcm_action(struct action_ops *ops, + struct snd_pcm_substream *substream, + int state) { int res; - if (snd_pcm_stream_linked(substream)) { + if (!snd_pcm_stream_linked(substream)) + return snd_pcm_action_single(ops, substream, state); + + if (substream->pcm->nonatomic) { if (!mutex_trylock(&substream->group->mutex)) { mutex_unlock(&substream->self_group.mutex); mutex_lock(&substream->group->mutex); @@ -916,24 +921,6 @@ static int snd_pcm_action_mutex(struct action_ops *ops, res = snd_pcm_action_group(ops, substream, state, 1); mutex_unlock(&substream->group->mutex); } else { - res = snd_pcm_action_single(ops, substream, state); - } - return res; -} - -/* - * Note: call with stream lock - */ -static int snd_pcm_action(struct action_ops *ops, - struct snd_pcm_substream *substream, - int state) -{ - int res; - - if (substream->pcm->nonatomic) - return snd_pcm_action_mutex(ops, substream, state); - - if (snd_pcm_stream_linked(substream)) { if (!spin_trylock(&substream->group->lock)) { spin_unlock(&substream->self_group.lock); spin_lock(&substream->group->lock); @@ -941,8 +928,6 @@ static int snd_pcm_action(struct action_ops *ops, } res = snd_pcm_action_group(ops, substream, state, 1); spin_unlock(&substream->group->lock); - } else { - res = snd_pcm_action_single(ops, substream, state); } return res; } -- cgit v1.2.3 From e369086968157415aeb11af3b57cd998c6721603 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Mon, 3 Nov 2014 16:04:12 +0530 Subject: ALSA: echoaudio: add reference of struct echoaudio added reference of struct echoaudio to free_firmware function. this structure will be later used to get a reference of the card when converting snd_printk to dev_* in the next patch of the series. Signed-off-by: Sudip Mukherjee Signed-off-by: Takashi Iwai --- sound/pci/echoaudio/echoaudio.c | 3 ++- sound/pci/echoaudio/echoaudio.h | 3 ++- sound/pci/echoaudio/echoaudio_dsp.c | 10 +++++----- 3 files changed, 9 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index d82321ff549b..db1b247d8587 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -69,7 +69,8 @@ static int get_firmware(const struct firmware **fw_entry, -static void free_firmware(const struct firmware *fw_entry) +static void free_firmware(const struct firmware *fw_entry, + struct echoaudio *chip) { #ifdef CONFIG_PM_SLEEP DE_ACT(("firmware not released (kept in cache)\n")); diff --git a/sound/pci/echoaudio/echoaudio.h b/sound/pci/echoaudio/echoaudio.h index b86b88da81cd..a4f112aa78e2 100644 --- a/sound/pci/echoaudio/echoaudio.h +++ b/sound/pci/echoaudio/echoaudio.h @@ -468,7 +468,8 @@ static int wait_handshake(struct echoaudio *chip); static int send_vector(struct echoaudio *chip, u32 command); static int get_firmware(const struct firmware **fw_entry, struct echoaudio *chip, const short fw_index); -static void free_firmware(const struct firmware *fw_entry); +static void free_firmware(const struct firmware *fw_entry, + struct echoaudio *chip); #ifdef ECHOCARD_HAS_MIDI static int enable_midi_input(struct echoaudio *chip, char enable); diff --git a/sound/pci/echoaudio/echoaudio_dsp.c b/sound/pci/echoaudio/echoaudio_dsp.c index 5a6a217b82e0..977b2bd2e72f 100644 --- a/sound/pci/echoaudio/echoaudio_dsp.c +++ b/sound/pci/echoaudio/echoaudio_dsp.c @@ -206,12 +206,12 @@ static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic) } DE_INIT(("ASIC loaded\n")); - free_firmware(fw); + free_firmware(fw, chip); return 0; la_error: DE_INIT(("failed on write_dsp\n")); - free_firmware(fw); + free_firmware(fw, chip); return -EIO; } @@ -317,11 +317,11 @@ static int install_resident_loader(struct echoaudio *chip) } DE_INIT(("Resident loader successfully installed\n")); - free_firmware(fw); + free_firmware(fw, chip); return 0; irl_error: - free_firmware(fw); + free_firmware(fw, chip); return -EIO; } @@ -491,7 +491,7 @@ static int load_firmware(struct echoaudio *chip) if (err < 0) return err; err = load_dsp(chip, (u16 *)fw->data); - free_firmware(fw); + free_firmware(fw, chip); if (err < 0) return err; -- cgit v1.2.3 From b5b4a41b392960010fccf1f9ccf8334d612bd450 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Mon, 3 Nov 2014 16:04:13 +0530 Subject: ALSA: echoaudio: remove all snd_printk removed all references of snd_printk with the standard dev_* macro. [a few places degraded to dev_dbg(), too -- tiwai] Signed-off-by: Sudip Mukherjee Signed-off-by: Takashi Iwai --- sound/pci/echoaudio/darla20_dsp.c | 7 +- sound/pci/echoaudio/darla24_dsp.c | 15 ++-- sound/pci/echoaudio/echo3g_dsp.c | 7 +- sound/pci/echoaudio/echoaudio.c | 137 ++++++++++++++++--------------- sound/pci/echoaudio/echoaudio.h | 28 ------- sound/pci/echoaudio/echoaudio_3g.c | 32 ++++---- sound/pci/echoaudio/echoaudio_dsp.c | 111 +++++++++++++++---------- sound/pci/echoaudio/echoaudio_gml.c | 11 +-- sound/pci/echoaudio/gina20_dsp.c | 15 ++-- sound/pci/echoaudio/gina24_dsp.c | 39 +++++---- sound/pci/echoaudio/indigo_dsp.c | 13 +-- sound/pci/echoaudio/indigo_express_dsp.c | 6 +- sound/pci/echoaudio/indigodj_dsp.c | 13 +-- sound/pci/echoaudio/indigodjx_dsp.c | 7 +- sound/pci/echoaudio/indigoio_dsp.c | 10 ++- sound/pci/echoaudio/indigoiox_dsp.c | 7 +- sound/pci/echoaudio/layla20_dsp.c | 37 +++++---- sound/pci/echoaudio/layla24_dsp.c | 34 ++++---- sound/pci/echoaudio/mia_dsp.c | 17 ++-- sound/pci/echoaudio/midi.c | 29 +++---- sound/pci/echoaudio/mona_dsp.c | 35 ++++---- 21 files changed, 327 insertions(+), 283 deletions(-) (limited to 'sound') diff --git a/sound/pci/echoaudio/darla20_dsp.c b/sound/pci/echoaudio/darla20_dsp.c index 20c7cbc89bb3..c94e92e31ae6 100644 --- a/sound/pci/echoaudio/darla20_dsp.c +++ b/sound/pci/echoaudio/darla20_dsp.c @@ -33,12 +33,13 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) { int err; - DE_INIT(("init_hw() - Darla20\n")); + dev_dbg(chip->card->dev, "init_hw() - Darla20\n"); if (snd_BUG_ON((subdevice_id & 0xfff0) != DARLA20)) return -ENODEV; if ((err = init_dsp_comm_page(chip))) { - DE_INIT(("init_hw - could not initialize DSP comm page\n")); + dev_err(chip->card->dev, + "init_hw: could not initialize DSP comm page\n"); return err; } @@ -57,7 +58,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - DE_INIT(("init_hw done\n")); + dev_dbg(chip->card->dev, "init_hw: done\n"); return err; } diff --git a/sound/pci/echoaudio/darla24_dsp.c b/sound/pci/echoaudio/darla24_dsp.c index 6da6663e9176..b1272f88d59d 100644 --- a/sound/pci/echoaudio/darla24_dsp.c +++ b/sound/pci/echoaudio/darla24_dsp.c @@ -33,12 +33,13 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) { int err; - DE_INIT(("init_hw() - Darla24\n")); + dev_dbg(chip->card->dev, "init_hw() - Darla24\n"); if (snd_BUG_ON((subdevice_id & 0xfff0) != DARLA24)) return -ENODEV; if ((err = init_dsp_comm_page(chip))) { - DE_INIT(("init_hw - could not initialize DSP comm page\n")); + dev_err(chip->card->dev, + "init_hw: could not initialize DSP comm page\n"); return err; } @@ -56,7 +57,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - DE_INIT(("init_hw done\n")); + dev_dbg(chip->card->dev, "init_hw: done\n"); return err; } @@ -128,15 +129,17 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate) clock = GD24_8000; break; default: - DE_ACT(("set_sample_rate: Error, invalid sample rate %d\n", - rate)); + dev_err(chip->card->dev, + "set_sample_rate: Error, invalid sample rate %d\n", + rate); return -EINVAL; } if (wait_handshake(chip)) return -EIO; - DE_ACT(("set_sample_rate: %d clock %d\n", rate, clock)); + dev_dbg(chip->card->dev, + "set_sample_rate: %d clock %d\n", rate, clock); chip->sample_rate = rate; /* Override the sample rate if this card is set to Echo sync. */ diff --git a/sound/pci/echoaudio/echo3g_dsp.c b/sound/pci/echoaudio/echo3g_dsp.c index 3cdc2ee2d1dd..bc3716895fc8 100644 --- a/sound/pci/echoaudio/echo3g_dsp.c +++ b/sound/pci/echoaudio/echo3g_dsp.c @@ -46,12 +46,13 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) int err; local_irq_enable(); - DE_INIT(("init_hw() - Echo3G\n")); + dev_dbg(chip->card->dev, "init_hw() - Echo3G\n"); if (snd_BUG_ON((subdevice_id & 0xfff0) != ECHO3G)) return -ENODEV; if ((err = init_dsp_comm_page(chip))) { - DE_INIT(("init_hw - could not initialize DSP comm page\n")); + dev_err(chip->card->dev, + "init_hw - could not initialize DSP comm page\n"); return err; } @@ -98,7 +99,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL | ECHOCAPS_HAS_DIGITAL_MODE_ADAT; - DE_INIT(("init_hw done\n")); + dev_dbg(chip->card->dev, "init_hw done\n"); return err; } diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index db1b247d8587..1ef29e5b53a7 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -48,13 +48,16 @@ static int get_firmware(const struct firmware **fw_entry, #ifdef CONFIG_PM_SLEEP if (chip->fw_cache[fw_index]) { - DE_ACT(("firmware requested: %s is cached\n", card_fw[fw_index].data)); + dev_dbg(chip->card->dev, + "firmware requested: %s is cached\n", + card_fw[fw_index].data); *fw_entry = chip->fw_cache[fw_index]; return 0; } #endif - DE_ACT(("firmware requested: %s\n", card_fw[fw_index].data)); + dev_dbg(chip->card->dev, + "firmware requested: %s\n", card_fw[fw_index].data); snprintf(name, sizeof(name), "ea/%s", card_fw[fw_index].data); err = request_firmware(fw_entry, name, pci_device(chip)); if (err < 0) @@ -73,10 +76,10 @@ static void free_firmware(const struct firmware *fw_entry, struct echoaudio *chip) { #ifdef CONFIG_PM_SLEEP - DE_ACT(("firmware not released (kept in cache)\n")); + dev_dbg(chip->card->dev, "firmware not released (kept in cache)\n"); #else release_firmware(fw_entry); - DE_ACT(("firmware released\n")); + dev_dbg(chip->card->dev, "firmware released\n"); #endif } @@ -90,10 +93,10 @@ static void free_firmware_cache(struct echoaudio *chip) for (i = 0; i < 8 ; i++) if (chip->fw_cache[i]) { release_firmware(chip->fw_cache[i]); - DE_ACT(("release_firmware(%d)\n", i)); + dev_dbg(chip->card->dev, "release_firmware(%d)\n", i); } - DE_ACT(("firmware_cache released\n")); + dev_dbg(chip->card->dev, "firmware_cache released\n"); #endif } @@ -287,7 +290,7 @@ static int pcm_open(struct snd_pcm_substream *substream, /* Set up hw capabilities and contraints */ memcpy(&pipe->hw, &pcm_hardware_skel, sizeof(struct snd_pcm_hardware)); - DE_HWP(("max_channels=%d\n", max_channels)); + dev_dbg(chip->card->dev, "max_channels=%d\n", max_channels); pipe->constr.list = channels_list; pipe->constr.mask = 0; for (i = 0; channels_list[i] <= max_channels; i++); @@ -337,7 +340,7 @@ static int pcm_open(struct snd_pcm_substream *substream, if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), PAGE_SIZE, &pipe->sgpage)) < 0) { - DE_HWP(("s-g list allocation failed\n")); + dev_err(chip->card->dev, "s-g list allocation failed\n"); return err; } @@ -351,7 +354,7 @@ static int pcm_analog_in_open(struct snd_pcm_substream *substream) struct echoaudio *chip = snd_pcm_substream_chip(substream); int err; - DE_ACT(("pcm_analog_in_open\n")); + dev_dbg(chip->card->dev, "pcm_analog_in_open\n"); if ((err = pcm_open(substream, num_analog_busses_in(chip) - substream->number)) < 0) return err; @@ -368,9 +371,9 @@ static int pcm_analog_in_open(struct snd_pcm_substream *substream) atomic_inc(&chip->opencount); if (atomic_read(&chip->opencount) > 1 && chip->rate_set) chip->can_set_rate=0; - DE_HWP(("pcm_analog_in_open cs=%d oc=%d r=%d\n", + dev_dbg(chip->card->dev, "pcm_analog_in_open cs=%d oc=%d r=%d\n", chip->can_set_rate, atomic_read(&chip->opencount), - chip->sample_rate)); + chip->sample_rate); return 0; } @@ -386,7 +389,7 @@ static int pcm_analog_out_open(struct snd_pcm_substream *substream) #else max_channels = num_analog_busses_out(chip); #endif - DE_ACT(("pcm_analog_out_open\n")); + dev_dbg(chip->card->dev, "pcm_analog_out_open\n"); if ((err = pcm_open(substream, max_channels - substream->number)) < 0) return err; if ((err = snd_pcm_hw_rule_add(substream->runtime, 0, @@ -404,9 +407,9 @@ static int pcm_analog_out_open(struct snd_pcm_substream *substream) atomic_inc(&chip->opencount); if (atomic_read(&chip->opencount) > 1 && chip->rate_set) chip->can_set_rate=0; - DE_HWP(("pcm_analog_out_open cs=%d oc=%d r=%d\n", + dev_dbg(chip->card->dev, "pcm_analog_out_open cs=%d oc=%d r=%d\n", chip->can_set_rate, atomic_read(&chip->opencount), - chip->sample_rate)); + chip->sample_rate); return 0; } @@ -419,7 +422,7 @@ static int pcm_digital_in_open(struct snd_pcm_substream *substream) struct echoaudio *chip = snd_pcm_substream_chip(substream); int err, max_channels; - DE_ACT(("pcm_digital_in_open\n")); + dev_dbg(chip->card->dev, "pcm_digital_in_open\n"); max_channels = num_digital_busses_in(chip) - substream->number; mutex_lock(&chip->mode_mutex); if (chip->digital_mode == DIGITAL_MODE_ADAT) @@ -461,7 +464,7 @@ static int pcm_digital_out_open(struct snd_pcm_substream *substream) struct echoaudio *chip = snd_pcm_substream_chip(substream); int err, max_channels; - DE_ACT(("pcm_digital_out_open\n")); + dev_dbg(chip->card->dev, "pcm_digital_out_open\n"); max_channels = num_digital_busses_out(chip) - substream->number; mutex_lock(&chip->mode_mutex); if (chip->digital_mode == DIGITAL_MODE_ADAT) @@ -508,18 +511,18 @@ static int pcm_close(struct snd_pcm_substream *substream) /* Nothing to do here. Audio is already off and pipe will be * freed by its callback */ - DE_ACT(("pcm_close\n")); + dev_dbg(chip->card->dev, "pcm_close\n"); atomic_dec(&chip->opencount); oc = atomic_read(&chip->opencount); - DE_ACT(("pcm_close oc=%d cs=%d rs=%d\n", oc, - chip->can_set_rate, chip->rate_set)); + dev_dbg(chip->card->dev, "pcm_close oc=%d cs=%d rs=%d\n", oc, + chip->can_set_rate, chip->rate_set); if (oc < 2) chip->can_set_rate = 1; if (oc == 0) chip->rate_set = 0; - DE_ACT(("pcm_close2 oc=%d cs=%d rs=%d\n", oc, - chip->can_set_rate,chip->rate_set)); + dev_dbg(chip->card->dev, "pcm_close2 oc=%d cs=%d rs=%d\n", oc, + chip->can_set_rate, chip->rate_set); return 0; } @@ -543,7 +546,7 @@ static int init_engine(struct snd_pcm_substream *substream, */ spin_lock_irq(&chip->lock); if (pipe->index >= 0) { - DE_HWP(("hwp_ie free(%d)\n", pipe->index)); + dev_dbg(chip->card->dev, "hwp_ie free(%d)\n", pipe->index); err = free_pipes(chip, pipe); snd_BUG_ON(err); chip->substream[pipe->index] = NULL; @@ -552,16 +555,17 @@ static int init_engine(struct snd_pcm_substream *substream, err = allocate_pipes(chip, pipe, pipe_index, interleave); if (err < 0) { spin_unlock_irq(&chip->lock); - DE_ACT((KERN_NOTICE "allocate_pipes(%d) err=%d\n", - pipe_index, err)); + dev_err(chip->card->dev, "allocate_pipes(%d) err=%d\n", + pipe_index, err); return err; } spin_unlock_irq(&chip->lock); - DE_ACT((KERN_NOTICE "allocate_pipes()=%d\n", pipe_index)); + dev_dbg(chip->card->dev, "allocate_pipes()=%d\n", pipe_index); - DE_HWP(("pcm_hw_params (bufsize=%dB periods=%d persize=%dB)\n", + dev_dbg(chip->card->dev, + "pcm_hw_params (bufsize=%dB periods=%d persize=%dB)\n", params_buffer_bytes(hw_params), params_periods(hw_params), - params_period_bytes(hw_params))); + params_period_bytes(hw_params)); err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (err < 0) { @@ -616,7 +620,7 @@ static int init_engine(struct snd_pcm_substream *substream, spin_lock_irq(&chip->lock); set_sample_rate(chip, hw_params->rate_num / hw_params->rate_den); spin_unlock_irq(&chip->lock); - DE_HWP(("pcm_hw_params ok\n")); + dev_dbg(chip->card->dev, "pcm_hw_params ok\n"); return 0; } @@ -680,14 +684,14 @@ static int pcm_hw_free(struct snd_pcm_substream *substream) spin_lock_irq(&chip->lock); if (pipe->index >= 0) { - DE_HWP(("pcm_hw_free(%d)\n", pipe->index)); + dev_dbg(chip->card->dev, "pcm_hw_free(%d)\n", pipe->index); free_pipes(chip, pipe); chip->substream[pipe->index] = NULL; pipe->index = -1; } spin_unlock_irq(&chip->lock); - DE_HWP(("pcm_hw_freed\n")); + dev_dbg(chip->card->dev, "pcm_hw_freed\n"); snd_pcm_lib_free_pages(substream); return 0; } @@ -701,8 +705,8 @@ static int pcm_prepare(struct snd_pcm_substream *substream) struct audioformat format; int pipe_index = ((struct audiopipe *)runtime->private_data)->index; - DE_HWP(("Prepare rate=%d format=%d channels=%d\n", - runtime->rate, runtime->format, runtime->channels)); + dev_dbg(chip->card->dev, "Prepare rate=%d format=%d channels=%d\n", + runtime->rate, runtime->format, runtime->channels); format.interleave = runtime->channels; format.data_are_bigendian = 0; format.mono_to_stereo = 0; @@ -722,8 +726,9 @@ static int pcm_prepare(struct snd_pcm_substream *substream) format.bits_per_sample = 32; break; default: - DE_HWP(("Prepare error: unsupported format %d\n", - runtime->format)); + dev_err(chip->card->dev, + "Prepare error: unsupported format %d\n", + runtime->format); return -EINVAL; } @@ -758,10 +763,10 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd) spin_lock(&chip->lock); switch (cmd) { case SNDRV_PCM_TRIGGER_RESUME: - DE_ACT(("pcm_trigger resume\n")); + dev_dbg(chip->card->dev, "pcm_trigger resume\n"); case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - DE_ACT(("pcm_trigger start\n")); + dev_dbg(chip->card->dev, "pcm_trigger start\n"); for (i = 0; i < DSP_MAXPIPES; i++) { if (channelmask & (1 << i)) { pipe = chip->substream[i]->runtime->private_data; @@ -783,9 +788,9 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd) chip->pipe_cyclic_mask); break; case SNDRV_PCM_TRIGGER_SUSPEND: - DE_ACT(("pcm_trigger suspend\n")); + dev_dbg(chip->card->dev, "pcm_trigger suspend\n"); case SNDRV_PCM_TRIGGER_STOP: - DE_ACT(("pcm_trigger stop\n")); + dev_dbg(chip->card->dev, "pcm_trigger stop\n"); for (i = 0; i < DSP_MAXPIPES; i++) { if (channelmask & (1 << i)) { pipe = chip->substream[i]->runtime->private_data; @@ -795,7 +800,7 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd) err = stop_transport(chip, channelmask); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - DE_ACT(("pcm_trigger pause\n")); + dev_dbg(chip->card->dev, "pcm_trigger pause\n"); for (i = 0; i < DSP_MAXPIPES; i++) { if (channelmask & (1 << i)) { pipe = chip->substream[i]->runtime->private_data; @@ -932,7 +937,7 @@ static int snd_echo_new_pcm(struct echoaudio *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &analog_capture_ops); if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0) return err; - DE_INIT(("Analog PCM ok\n")); + dev_dbg(chip->card->dev, "Analog PCM ok\n"); #ifdef ECHOCARD_HAS_DIGITAL_IO /* PCM#1 Digital inputs, no outputs */ @@ -945,7 +950,7 @@ static int snd_echo_new_pcm(struct echoaudio *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &digital_capture_ops); if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0) return err; - DE_INIT(("Digital PCM ok\n")); + dev_dbg(chip->card->dev, "Digital PCM ok\n"); #endif /* ECHOCARD_HAS_DIGITAL_IO */ #else /* ECHOCARD_HAS_VMIXER */ @@ -967,7 +972,7 @@ static int snd_echo_new_pcm(struct echoaudio *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &analog_capture_ops); if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0) return err; - DE_INIT(("Analog PCM ok\n")); + dev_dbg(chip->card->dev, "Analog PCM ok\n"); #ifdef ECHOCARD_HAS_DIGITAL_IO /* PCM#1 Digital i/o */ @@ -982,7 +987,7 @@ static int snd_echo_new_pcm(struct echoaudio *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &digital_capture_ops); if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0) return err; - DE_INIT(("Digital PCM ok\n")); + dev_dbg(chip->card->dev, "Digital PCM ok\n"); #endif /* ECHOCARD_HAS_DIGITAL_IO */ #endif /* ECHOCARD_HAS_VMIXER */ @@ -1475,7 +1480,8 @@ static int snd_echo_digital_mode_put(struct snd_kcontrol *kcontrol, snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->clock_src_ctl->id); - DE_ACT(("SDM() =%d\n", changed)); + dev_dbg(chip->card->dev, + "SDM() =%d\n", changed); } if (changed >= 0) changed = 1; /* No errors */ @@ -1602,7 +1608,8 @@ static int snd_echo_clock_source_put(struct snd_kcontrol *kcontrol, } if (changed < 0) - DE_ACT(("seticlk val%d err 0x%x\n", dclock, changed)); + dev_dbg(chip->card->dev, + "seticlk val%d err 0x%x\n", dclock, changed); return changed; } @@ -1859,7 +1866,7 @@ static irqreturn_t snd_echo_interrupt(int irq, void *dev_id) #ifdef ECHOCARD_HAS_MIDI if (st > 0 && chip->midi_in) { snd_rawmidi_receive(chip->midi_in, chip->midi_buffer, st); - DE_MID(("rawmidi_iread=%d\n", st)); + dev_dbg(chip->card->dev, "rawmidi_iread=%d\n", st); } #endif return IRQ_HANDLED; @@ -1874,10 +1881,10 @@ static irqreturn_t snd_echo_interrupt(int irq, void *dev_id) static int snd_echo_free(struct echoaudio *chip) { - DE_INIT(("Stop DSP...\n")); + dev_dbg(chip->card->dev, "Stop DSP...\n"); if (chip->comm_page) rest_in_peace(chip); - DE_INIT(("Stopped.\n")); + dev_dbg(chip->card->dev, "Stopped.\n"); if (chip->irq >= 0) free_irq(chip->irq, chip); @@ -1891,14 +1898,14 @@ static int snd_echo_free(struct echoaudio *chip) if (chip->iores) release_and_free_resource(chip->iores); - DE_INIT(("MMIO freed.\n")); + dev_dbg(chip->card->dev, "MMIO freed.\n"); pci_disable_device(chip->pci); /* release chip data */ free_firmware_cache(chip); kfree(chip); - DE_INIT(("Chip freed.\n")); + dev_dbg(chip->card->dev, "Chip freed.\n"); return 0; } @@ -1908,7 +1915,7 @@ static int snd_echo_dev_free(struct snd_device *device) { struct echoaudio *chip = device->device_data; - DE_INIT(("snd_echo_dev_free()...\n")); + dev_dbg(chip->card->dev, "snd_echo_dev_free()...\n"); return snd_echo_free(chip); } @@ -1941,7 +1948,7 @@ static int snd_echo_create(struct snd_card *card, pci_disable_device(pci); return -ENOMEM; } - DE_INIT(("chip=%p\n", chip)); + dev_dbg(card->dev, "chip=%p\n", chip); spin_lock_init(&chip->lock); chip->card = card; chip->pci = pci; @@ -1978,8 +1985,8 @@ static int snd_echo_create(struct snd_card *card, return -EBUSY; } chip->irq = pci->irq; - DE_INIT(("pci=%p irq=%d subdev=%04x Init hardware...\n", - chip->pci, chip->irq, chip->pci->subsystem_device)); + dev_dbg(card->dev, "pci=%p irq=%d subdev=%04x Init hardware...\n", + chip->pci, chip->irq, chip->pci->subsystem_device); /* Create the DSP comm page - this is the area of memory used for most of the communication with the DSP, which accesses it via bus mastering */ @@ -1997,11 +2004,11 @@ static int snd_echo_create(struct snd_card *card, if (err >= 0) err = set_mixer_defaults(chip); if (err < 0) { - DE_INIT(("init_hw err=%d\n", err)); + dev_err(card->dev, "init_hw err=%d\n", err); snd_echo_free(chip); return err; } - DE_INIT(("Card init OK\n")); + dev_dbg(card->dev, "Card init OK\n"); if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_echo_free(chip); @@ -2031,7 +2038,7 @@ static int snd_echo_probe(struct pci_dev *pci, return -ENOENT; } - DE_INIT(("Echoaudio driver starting...\n")); + dev_dbg(&pci->dev, "Echoaudio driver starting...\n"); i = 0; err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, 0, &card); @@ -2184,7 +2191,7 @@ static int snd_echo_suspend(struct device *dev) struct pci_dev *pci = to_pci_dev(dev); struct echoaudio *chip = dev_get_drvdata(dev); - DE_INIT(("suspend start\n")); + dev_dbg(dev, "suspend start\n"); snd_pcm_suspend_all(chip->analog_pcm); snd_pcm_suspend_all(chip->digital_pcm); @@ -2211,7 +2218,7 @@ static int snd_echo_suspend(struct device *dev) pci_save_state(pci); pci_disable_device(pci); - DE_INIT(("suspend done\n")); + dev_dbg(dev, "suspend done\n"); return 0; } @@ -2225,7 +2232,7 @@ static int snd_echo_resume(struct device *dev) u32 pipe_alloc_mask; int err; - DE_INIT(("resume start\n")); + dev_dbg(dev, "resume start\n"); pci_restore_state(pci); commpage_bak = kmalloc(sizeof(struct echoaudio), GFP_KERNEL); if (commpage_bak == NULL) @@ -2236,11 +2243,11 @@ static int snd_echo_resume(struct device *dev) err = init_hw(chip, chip->pci->device, chip->pci->subsystem_device); if (err < 0) { kfree(commpage_bak); - DE_INIT(("resume init_hw err=%d\n", err)); + dev_err(dev, "resume init_hw err=%d\n", err); snd_echo_free(chip); return err; } - DE_INIT(("resume init OK\n")); + dev_dbg(dev, "resume init OK\n"); /* Temporarily set chip->pipe_alloc_mask=0 otherwise * restore_dsp_settings() fails. @@ -2253,7 +2260,7 @@ static int snd_echo_resume(struct device *dev) kfree(commpage_bak); return err; } - DE_INIT(("resume restore OK\n")); + dev_dbg(dev, "resume restore OK\n"); memcpy(&commpage->audio_format, &commpage_bak->audio_format, sizeof(commpage->audio_format)); @@ -2270,7 +2277,7 @@ static int snd_echo_resume(struct device *dev) return -EBUSY; } chip->irq = pci->irq; - DE_INIT(("resume irq=%d\n", chip->irq)); + dev_dbg(dev, "resume irq=%d\n", chip->irq); #ifdef ECHOCARD_HAS_MIDI if (chip->midi_input_enabled) @@ -2279,7 +2286,7 @@ static int snd_echo_resume(struct device *dev) snd_echo_midi_output_trigger(chip->midi_out, 1); #endif - DE_INIT(("resume done\n")); + dev_dbg(dev, "resume done\n"); return 0; } diff --git a/sound/pci/echoaudio/echoaudio.h b/sound/pci/echoaudio/echoaudio.h index a4f112aa78e2..32515227a692 100644 --- a/sound/pci/echoaudio/echoaudio.h +++ b/sound/pci/echoaudio/echoaudio.h @@ -295,34 +295,6 @@ #define PIPE_STATE_PENDING 3 /* Pipe has pending start */ -/* Debug initialization */ -#ifdef CONFIG_SND_DEBUG -#define DE_INIT(x) snd_printk x -#else -#define DE_INIT(x) -#endif - -/* Debug hw_params callbacks */ -#ifdef CONFIG_SND_DEBUG -#define DE_HWP(x) snd_printk x -#else -#define DE_HWP(x) -#endif - -/* Debug normal activity (open, start, stop...) */ -#ifdef CONFIG_SND_DEBUG -#define DE_ACT(x) snd_printk x -#else -#define DE_ACT(x) -#endif - -/* Debug midi activity */ -#ifdef CONFIG_SND_DEBUG -#define DE_MID(x) snd_printk x -#else -#define DE_MID(x) -#endif - struct audiopipe { volatile u32 *dma_counter; /* Commpage register that contains diff --git a/sound/pci/echoaudio/echoaudio_3g.c b/sound/pci/echoaudio/echoaudio_3g.c index 658db44ef746..50a21690447d 100644 --- a/sound/pci/echoaudio/echoaudio_3g.c +++ b/sound/pci/echoaudio/echoaudio_3g.c @@ -51,7 +51,7 @@ static int check_asic_status(struct echoaudio *chip) } box_status = le32_to_cpu(chip->comm_page->ext_box_status); - DE_INIT(("box_status=%x\n", box_status)); + dev_dbg(chip->card->dev, "box_status=%x\n", box_status); if (box_status == E3G_ASIC_NOT_LOADED) return -ENODEV; @@ -76,7 +76,8 @@ static int write_control_reg(struct echoaudio *chip, u32 ctl, u32 frq, if (wait_handshake(chip)) return -EIO; - DE_ACT(("WriteControlReg: Setting 0x%x, 0x%x\n", ctl, frq)); + dev_dbg(chip->card->dev, + "WriteControlReg: Setting 0x%x, 0x%x\n", ctl, frq); ctl = cpu_to_le32(ctl); frq = cpu_to_le32(frq); @@ -89,7 +90,7 @@ static int write_control_reg(struct echoaudio *chip, u32 ctl, u32 frq, return send_vector(chip, DSP_VC_WRITE_CONTROL_REG); } - DE_ACT(("WriteControlReg: not written, no change\n")); + dev_dbg(chip->card->dev, "WriteControlReg: not written, no change\n"); return 0; } @@ -258,8 +259,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate) /* Only set the clock for internal mode. */ if (chip->input_clock != ECHO_CLOCK_INTERNAL) { - DE_ACT(("set_sample_rate: Cannot set sample rate - " - "clock not set to CLK_CLOCKININTERNAL\n")); + dev_warn(chip->card->dev, + "Cannot set sample rate - clock not set to CLK_CLOCKININTERNAL\n"); /* Save the rate anyhow */ chip->comm_page->sample_rate = cpu_to_le32(rate); chip->sample_rate = rate; @@ -313,7 +314,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate) chip->comm_page->sample_rate = cpu_to_le32(rate); /* ignored by the DSP */ chip->sample_rate = rate; - DE_ACT(("SetSampleRate: %d clock %x\n", rate, control_reg)); + dev_dbg(chip->card->dev, + "SetSampleRate: %d clock %x\n", rate, control_reg); /* Tell the DSP about it - DSP reads both control reg & freq reg */ return write_control_reg(chip, control_reg, frq_reg, 0); @@ -326,7 +328,7 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) { u32 control_reg, clocks_from_dsp; - DE_ACT(("set_input_clock:\n")); + dev_dbg(chip->card->dev, "set_input_clock:\n"); /* Mask off the clock select bits */ control_reg = le32_to_cpu(chip->comm_page->control_register) & @@ -335,13 +337,13 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) switch (clock) { case ECHO_CLOCK_INTERNAL: - DE_ACT(("Set Echo3G clock to INTERNAL\n")); + dev_dbg(chip->card->dev, "Set Echo3G clock to INTERNAL\n"); chip->input_clock = ECHO_CLOCK_INTERNAL; return set_sample_rate(chip, chip->sample_rate); case ECHO_CLOCK_SPDIF: if (chip->digital_mode == DIGITAL_MODE_ADAT) return -EAGAIN; - DE_ACT(("Set Echo3G clock to SPDIF\n")); + dev_dbg(chip->card->dev, "Set Echo3G clock to SPDIF\n"); control_reg |= E3G_SPDIF_CLOCK; if (clocks_from_dsp & E3G_CLOCK_DETECT_BIT_SPDIF96) control_reg |= E3G_DOUBLE_SPEED_MODE; @@ -351,12 +353,12 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) case ECHO_CLOCK_ADAT: if (chip->digital_mode != DIGITAL_MODE_ADAT) return -EAGAIN; - DE_ACT(("Set Echo3G clock to ADAT\n")); + dev_dbg(chip->card->dev, "Set Echo3G clock to ADAT\n"); control_reg |= E3G_ADAT_CLOCK; control_reg &= ~E3G_DOUBLE_SPEED_MODE; break; case ECHO_CLOCK_WORD: - DE_ACT(("Set Echo3G clock to WORD\n")); + dev_dbg(chip->card->dev, "Set Echo3G clock to WORD\n"); control_reg |= E3G_WORD_CLOCK; if (clocks_from_dsp & E3G_CLOCK_DETECT_BIT_WORD96) control_reg |= E3G_DOUBLE_SPEED_MODE; @@ -364,7 +366,8 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) control_reg &= ~E3G_DOUBLE_SPEED_MODE; break; default: - DE_ACT(("Input clock 0x%x not supported for Echo3G\n", clock)); + dev_err(chip->card->dev, + "Input clock 0x%x not supported for Echo3G\n", clock); return -EINVAL; } @@ -392,7 +395,8 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode) incompatible_clock = TRUE; break; default: - DE_ACT(("Digital mode not supported: %d\n", mode)); + dev_err(chip->card->dev, + "Digital mode not supported: %d\n", mode); return -EINVAL; } @@ -427,6 +431,6 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode) return err; chip->digital_mode = mode; - DE_ACT(("set_digital_mode(%d)\n", chip->digital_mode)); + dev_dbg(chip->card->dev, "set_digital_mode(%d)\n", chip->digital_mode); return incompatible_clock; } diff --git a/sound/pci/echoaudio/echoaudio_dsp.c b/sound/pci/echoaudio/echoaudio_dsp.c index 977b2bd2e72f..ba9d4f16cbb3 100644 --- a/sound/pci/echoaudio/echoaudio_dsp.c +++ b/sound/pci/echoaudio/echoaudio_dsp.c @@ -80,7 +80,7 @@ static int send_vector(struct echoaudio *chip, u32 command) udelay(1); } - DE_ACT((KERN_ERR "timeout on send_vector\n")); + dev_err(chip->card->dev, "timeout on send_vector\n"); return -EBUSY; } @@ -104,7 +104,7 @@ static int write_dsp(struct echoaudio *chip, u32 data) } chip->bad_board = TRUE; /* Set TRUE until DSP re-loaded */ - DE_ACT((KERN_ERR "write_dsp: Set bad_board to TRUE\n")); + dev_dbg(chip->card->dev, "write_dsp: Set bad_board to TRUE\n"); return -EIO; } @@ -127,7 +127,7 @@ static int read_dsp(struct echoaudio *chip, u32 *data) } chip->bad_board = TRUE; /* Set TRUE until DSP re-loaded */ - DE_INIT((KERN_ERR "read_dsp: Set bad_board to TRUE\n")); + dev_err(chip->card->dev, "read_dsp: Set bad_board to TRUE\n"); return -EIO; } @@ -154,8 +154,9 @@ static int read_sn(struct echoaudio *chip) return -EIO; } } - DE_INIT(("Read serial number %08x %08x %08x %08x %08x\n", - sn[0], sn[1], sn[2], sn[3], sn[4])); + dev_dbg(chip->card->dev, + "Read serial number %08x %08x %08x %08x %08x\n", + sn[0], sn[1], sn[2], sn[3], sn[4]); return 0; } @@ -205,12 +206,12 @@ static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic) goto la_error; } - DE_INIT(("ASIC loaded\n")); + dev_dbg(chip->card->dev, "ASIC loaded\n"); free_firmware(fw, chip); return 0; la_error: - DE_INIT(("failed on write_dsp\n")); + dev_err(chip->card->dev, "failed on write_dsp\n"); free_firmware(fw, chip); return -EIO; } @@ -241,8 +242,9 @@ static int install_resident_loader(struct echoaudio *chip) loader is already installed, host flag 5 will be on. */ status = get_dsp_register(chip, CHI32_STATUS_REG); if (status & CHI32_STATUS_REG_HF5) { - DE_INIT(("Resident loader already installed; status is 0x%x\n", - status)); + dev_dbg(chip->card->dev, + "Resident loader already installed; status is 0x%x\n", + status); return 0; } @@ -283,12 +285,14 @@ static int install_resident_loader(struct echoaudio *chip) /* Write the count to the DSP */ if (write_dsp(chip, words)) { - DE_INIT(("install_resident_loader: Failed to write word count!\n")); + dev_err(chip->card->dev, + "install_resident_loader: Failed to write word count!\n"); goto irl_error; } /* Write the DSP address */ if (write_dsp(chip, address)) { - DE_INIT(("install_resident_loader: Failed to write DSP address!\n")); + dev_err(chip->card->dev, + "install_resident_loader: Failed to write DSP address!\n"); goto irl_error; } /* Write out this block of code to the DSP */ @@ -297,7 +301,8 @@ static int install_resident_loader(struct echoaudio *chip) data = ((u32)code[index] << 16) + code[index + 1]; if (write_dsp(chip, data)) { - DE_INIT(("install_resident_loader: Failed to write DSP code\n")); + dev_err(chip->card->dev, + "install_resident_loader: Failed to write DSP code\n"); goto irl_error; } index += 2; @@ -312,11 +317,11 @@ static int install_resident_loader(struct echoaudio *chip) } if (i == 200) { - DE_INIT(("Resident loader failed to set HF5\n")); + dev_err(chip->card->dev, "Resident loader failed to set HF5\n"); goto irl_error; } - DE_INIT(("Resident loader successfully installed\n")); + dev_dbg(chip->card->dev, "Resident loader successfully installed\n"); free_firmware(fw, chip); return 0; @@ -334,14 +339,14 @@ static int load_dsp(struct echoaudio *chip, u16 *code) int index, words, i; if (chip->dsp_code == code) { - DE_INIT(("DSP is already loaded!\n")); + dev_warn(chip->card->dev, "DSP is already loaded!\n"); return 0; } chip->bad_board = TRUE; /* Set TRUE until DSP loaded */ chip->dsp_code = NULL; /* Current DSP code not loaded */ chip->asic_loaded = FALSE; /* Loading the DSP code will reset the ASIC */ - DE_INIT(("load_dsp: Set bad_board to TRUE\n")); + dev_dbg(chip->card->dev, "load_dsp: Set bad_board to TRUE\n"); /* If this board requires a resident loader, install it. */ #ifdef DSP_56361 @@ -351,7 +356,8 @@ static int load_dsp(struct echoaudio *chip, u16 *code) /* Send software reset command */ if (send_vector(chip, DSP_VC_RESET) < 0) { - DE_INIT(("LoadDsp: send_vector DSP_VC_RESET failed, Critical Failure\n")); + dev_err(chip->card->dev, + "LoadDsp: send_vector DSP_VC_RESET failed, Critical Failure\n"); return -EIO; } /* Delay 10us */ @@ -366,7 +372,8 @@ static int load_dsp(struct echoaudio *chip, u16 *code) } if (i == 1000) { - DE_INIT(("load_dsp: Timeout waiting for CHI32_STATUS_REG_HF3\n")); + dev_err(chip->card->dev, + "load_dsp: Timeout waiting for CHI32_STATUS_REG_HF3\n"); return -EIO; } @@ -403,29 +410,34 @@ static int load_dsp(struct echoaudio *chip, u16 *code) index += 2; if (write_dsp(chip, words) < 0) { - DE_INIT(("load_dsp: failed to write number of DSP words\n")); + dev_err(chip->card->dev, + "load_dsp: failed to write number of DSP words\n"); return -EIO; } if (write_dsp(chip, address) < 0) { - DE_INIT(("load_dsp: failed to write DSP address\n")); + dev_err(chip->card->dev, + "load_dsp: failed to write DSP address\n"); return -EIO; } if (write_dsp(chip, mem_type) < 0) { - DE_INIT(("load_dsp: failed to write DSP memory type\n")); + dev_err(chip->card->dev, + "load_dsp: failed to write DSP memory type\n"); return -EIO; } /* Code */ for (i = 0; i < words; i++, index+=2) { data = ((u32)code[index] << 16) + code[index + 1]; if (write_dsp(chip, data) < 0) { - DE_INIT(("load_dsp: failed to write DSP data\n")); + dev_err(chip->card->dev, + "load_dsp: failed to write DSP data\n"); return -EIO; } } } if (write_dsp(chip, 0) < 0) { /* We're done!!! */ - DE_INIT(("load_dsp: Failed to write final zero\n")); + dev_err(chip->card->dev, + "load_dsp: Failed to write final zero\n"); return -EIO; } udelay(10); @@ -438,12 +450,14 @@ static int load_dsp(struct echoaudio *chip, u16 *code) get_dsp_register(chip, CHI32_CONTROL_REG) & ~0x1b00); if (write_dsp(chip, DSP_FNC_SET_COMMPAGE_ADDR) < 0) { - DE_INIT(("load_dsp: Failed to write DSP_FNC_SET_COMMPAGE_ADDR\n")); + dev_err(chip->card->dev, + "load_dsp: Failed to write DSP_FNC_SET_COMMPAGE_ADDR\n"); return -EIO; } if (write_dsp(chip, chip->comm_page_phys) < 0) { - DE_INIT(("load_dsp: Failed to write comm page address\n")); + dev_err(chip->card->dev, + "load_dsp: Failed to write comm page address\n"); return -EIO; } @@ -452,19 +466,21 @@ static int load_dsp(struct echoaudio *chip, u16 *code) We don't actually use the serial number but we have to get it as part of the DSP init voodoo. */ if (read_sn(chip) < 0) { - DE_INIT(("load_dsp: Failed to read serial number\n")); + dev_err(chip->card->dev, + "load_dsp: Failed to read serial number\n"); return -EIO; } chip->dsp_code = code; /* Show which DSP code loaded */ chip->bad_board = FALSE; /* DSP OK */ - DE_INIT(("load_dsp: OK!\n")); + dev_dbg(chip->card->dev, "load_dsp: OK!\n"); return 0; } udelay(100); } - DE_INIT(("load_dsp: DSP load timed out waiting for HF4\n")); + dev_err(chip->card->dev, + "load_dsp: DSP load timed out waiting for HF4\n"); return -EIO; } @@ -658,7 +674,7 @@ static void get_audio_meters(struct echoaudio *chip, long *meters) static int restore_dsp_rettings(struct echoaudio *chip) { int i, o, err; - DE_INIT(("restore_dsp_settings\n")); + dev_dbg(chip->card->dev, "restore_dsp_settings\n"); if ((err = check_asic_status(chip)) < 0) return err; @@ -755,7 +771,7 @@ static int restore_dsp_rettings(struct echoaudio *chip) if (send_vector(chip, DSP_VC_UPDATE_FLAGS) < 0) return -EIO; - DE_INIT(("restore_dsp_rettings done\n")); + dev_dbg(chip->card->dev, "restore_dsp_rettings done\n"); return 0; } @@ -835,7 +851,8 @@ static void set_audio_format(struct echoaudio *chip, u16 pipe_index, break; } } - DE_ACT(("set_audio_format[%d] = %x\n", pipe_index, dsp_format)); + dev_dbg(chip->card->dev, + "set_audio_format[%d] = %x\n", pipe_index, dsp_format); chip->comm_page->audio_format[pipe_index] = cpu_to_le16(dsp_format); } @@ -848,7 +865,7 @@ Same thing for pause_ and stop_ -trasport below. */ static int start_transport(struct echoaudio *chip, u32 channel_mask, u32 cyclic_mask) { - DE_ACT(("start_transport %x\n", channel_mask)); + dev_dbg(chip->card->dev, "start_transport %x\n", channel_mask); if (wait_handshake(chip)) return -EIO; @@ -866,7 +883,7 @@ static int start_transport(struct echoaudio *chip, u32 channel_mask, return 0; } - DE_ACT(("start_transport: No pipes to start!\n")); + dev_err(chip->card->dev, "start_transport: No pipes to start!\n"); return -EINVAL; } @@ -874,7 +891,7 @@ static int start_transport(struct echoaudio *chip, u32 channel_mask, static int pause_transport(struct echoaudio *chip, u32 channel_mask) { - DE_ACT(("pause_transport %x\n", channel_mask)); + dev_dbg(chip->card->dev, "pause_transport %x\n", channel_mask); if (wait_handshake(chip)) return -EIO; @@ -893,7 +910,7 @@ static int pause_transport(struct echoaudio *chip, u32 channel_mask) return 0; } - DE_ACT(("pause_transport: No pipes to stop!\n")); + dev_warn(chip->card->dev, "pause_transport: No pipes to stop!\n"); return 0; } @@ -901,7 +918,7 @@ static int pause_transport(struct echoaudio *chip, u32 channel_mask) static int stop_transport(struct echoaudio *chip, u32 channel_mask) { - DE_ACT(("stop_transport %x\n", channel_mask)); + dev_dbg(chip->card->dev, "stop_transport %x\n", channel_mask); if (wait_handshake(chip)) return -EIO; @@ -920,7 +937,7 @@ static int stop_transport(struct echoaudio *chip, u32 channel_mask) return 0; } - DE_ACT(("stop_transport: No pipes to stop!\n")); + dev_warn(chip->card->dev, "stop_transport: No pipes to stop!\n"); return 0; } @@ -937,7 +954,8 @@ static inline int is_pipe_allocated(struct echoaudio *chip, u16 pipe_index) stopped and unallocated. */ static int rest_in_peace(struct echoaudio *chip) { - DE_ACT(("rest_in_peace() open=%x\n", chip->pipe_alloc_mask)); + dev_dbg(chip->card->dev, + "rest_in_peace() open=%x\n", chip->pipe_alloc_mask); /* Stops all active pipes (just to be sure) */ stop_transport(chip, chip->active_mask); @@ -965,7 +983,8 @@ static int init_dsp_comm_page(struct echoaudio *chip) { /* Check if the compiler added extra padding inside the structure */ if (offsetof(struct comm_page, midi_output) != 0xbe0) { - DE_INIT(("init_dsp_comm_page() - Invalid struct comm_page structure\n")); + dev_err(chip->card->dev, + "init_dsp_comm_page() - Invalid struct comm_page structure\n"); return -EPERM; } @@ -999,7 +1018,7 @@ static int init_dsp_comm_page(struct echoaudio *chip) */ static int init_line_levels(struct echoaudio *chip) { - DE_INIT(("init_line_levels\n")); + dev_dbg(chip->card->dev, "init_line_levels\n"); memset(chip->output_gain, ECHOGAIN_MUTED, sizeof(chip->output_gain)); memset(chip->input_gain, ECHOGAIN_MUTED, sizeof(chip->input_gain)); memset(chip->monitor_gain, ECHOGAIN_MUTED, sizeof(chip->monitor_gain)); @@ -1051,7 +1070,8 @@ static int allocate_pipes(struct echoaudio *chip, struct audiopipe *pipe, u32 channel_mask; char is_cyclic; - DE_ACT(("allocate_pipes: ch=%d int=%d\n", pipe_index, interleave)); + dev_dbg(chip->card->dev, + "allocate_pipes: ch=%d int=%d\n", pipe_index, interleave); if (chip->bad_board) return -EIO; @@ -1061,7 +1081,8 @@ static int allocate_pipes(struct echoaudio *chip, struct audiopipe *pipe, for (channel_mask = i = 0; i < interleave; i++) channel_mask |= 1 << (pipe_index + i); if (chip->pipe_alloc_mask & channel_mask) { - DE_ACT(("allocate_pipes: channel already open\n")); + dev_err(chip->card->dev, + "allocate_pipes: channel already open\n"); return -EAGAIN; } @@ -1078,7 +1099,7 @@ static int allocate_pipes(struct echoaudio *chip, struct audiopipe *pipe, it moves data. The DMA counter is in units of bytes, not samples. */ pipe->dma_counter = &chip->comm_page->position[pipe_index]; *pipe->dma_counter = 0; - DE_ACT(("allocate_pipes: ok\n")); + dev_dbg(chip->card->dev, "allocate_pipes: ok\n"); return pipe_index; } @@ -1089,7 +1110,7 @@ static int free_pipes(struct echoaudio *chip, struct audiopipe *pipe) u32 channel_mask; int i; - DE_ACT(("free_pipes: Pipe %d\n", pipe->index)); + dev_dbg(chip->card->dev, "free_pipes: Pipe %d\n", pipe->index); if (snd_BUG_ON(!is_pipe_allocated(chip, pipe->index))) return -EINVAL; if (snd_BUG_ON(pipe->state != PIPE_STATE_STOPPED)) @@ -1131,7 +1152,7 @@ static int sglist_add_mapping(struct echoaudio *chip, struct audiopipe *pipe, list[head].size = cpu_to_le32(length); pipe->sglist_head++; } else { - DE_ACT(("SGlist: too many fragments\n")); + dev_err(chip->card->dev, "SGlist: too many fragments\n"); return -ENOMEM; } return 0; diff --git a/sound/pci/echoaudio/echoaudio_gml.c b/sound/pci/echoaudio/echoaudio_gml.c index afa273330e8a..23a099425834 100644 --- a/sound/pci/echoaudio/echoaudio_gml.c +++ b/sound/pci/echoaudio/echoaudio_gml.c @@ -46,7 +46,8 @@ static int check_asic_status(struct echoaudio *chip) /* The DSP will return a value to indicate whether or not the ASIC is currently loaded */ if (read_dsp(chip, &asic_status) < 0) { - DE_INIT(("check_asic_status: failed on read_dsp\n")); + dev_err(chip->card->dev, + "check_asic_status: failed on read_dsp\n"); chip->asic_loaded = FALSE; return -EIO; } @@ -68,7 +69,7 @@ static int write_control_reg(struct echoaudio *chip, u32 value, char force) else value &= ~GML_DIGITAL_IN_AUTO_MUTE; - DE_ACT(("write_control_reg: 0x%x\n", value)); + dev_dbg(chip->card->dev, "write_control_reg: 0x%x\n", value); /* Write the control register */ value = cpu_to_le32(value); @@ -91,7 +92,7 @@ If the auto-mute is disabled, the digital inputs are enabled regardless of what the input clock is set or what is connected. */ static int set_input_auto_mute(struct echoaudio *chip, int automute) { - DE_ACT(("set_input_auto_mute %d\n", automute)); + dev_dbg(chip->card->dev, "set_input_auto_mute %d\n", automute); chip->digital_in_automute = automute; @@ -194,7 +195,7 @@ static int set_professional_spdif(struct echoaudio *chip, char prof) if ((err = write_control_reg(chip, control_reg, FALSE))) return err; chip->professional_spdif = prof; - DE_ACT(("set_professional_spdif to %s\n", - prof ? "Professional" : "Consumer")); + dev_dbg(chip->card->dev, "set_professional_spdif to %s\n", + prof ? "Professional" : "Consumer"); return 0; } diff --git a/sound/pci/echoaudio/gina20_dsp.c b/sound/pci/echoaudio/gina20_dsp.c index d1615a0579d1..a959eae95e0d 100644 --- a/sound/pci/echoaudio/gina20_dsp.c +++ b/sound/pci/echoaudio/gina20_dsp.c @@ -37,12 +37,13 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) { int err; - DE_INIT(("init_hw() - Gina20\n")); + dev_dbg(chip->card->dev, "init_hw() - Gina20\n"); if (snd_BUG_ON((subdevice_id & 0xfff0) != GINA20)) return -ENODEV; if ((err = init_dsp_comm_page(chip))) { - DE_INIT(("init_hw - could not initialize DSP comm page\n")); + dev_err(chip->card->dev, + "init_hw - could not initialize DSP comm page\n"); return err; } @@ -62,7 +63,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - DE_INIT(("init_hw done\n")); + dev_dbg(chip->card->dev, "init_hw done\n"); return err; } @@ -149,7 +150,7 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate) static int set_input_clock(struct echoaudio *chip, u16 clock) { - DE_ACT(("set_input_clock:\n")); + dev_dbg(chip->card->dev, "set_input_clock:\n"); switch (clock) { case ECHO_CLOCK_INTERNAL: @@ -158,7 +159,7 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) chip->spdif_status = GD_SPDIF_STATUS_UNDEF; set_sample_rate(chip, chip->sample_rate); chip->input_clock = clock; - DE_ACT(("Set Gina clock to INTERNAL\n")); + dev_dbg(chip->card->dev, "Set Gina clock to INTERNAL\n"); break; case ECHO_CLOCK_SPDIF: chip->comm_page->gd_clock_state = GD_CLOCK_SPDIFIN; @@ -166,7 +167,7 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) clear_handshake(chip); send_vector(chip, DSP_VC_SET_GD_AUDIO_STATE); chip->clock_state = GD_CLOCK_SPDIFIN; - DE_ACT(("Set Gina20 clock to SPDIF\n")); + dev_dbg(chip->card->dev, "Set Gina20 clock to SPDIF\n"); chip->input_clock = clock; break; default: @@ -208,7 +209,7 @@ static int update_flags(struct echoaudio *chip) static int set_professional_spdif(struct echoaudio *chip, char prof) { - DE_ACT(("set_professional_spdif %d\n", prof)); + dev_dbg(chip->card->dev, "set_professional_spdif %d\n", prof); if (prof) chip->comm_page->flags |= cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF); diff --git a/sound/pci/echoaudio/gina24_dsp.c b/sound/pci/echoaudio/gina24_dsp.c index 98f7cfa81b5f..c8ea57612d22 100644 --- a/sound/pci/echoaudio/gina24_dsp.c +++ b/sound/pci/echoaudio/gina24_dsp.c @@ -41,12 +41,13 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) { int err; - DE_INIT(("init_hw() - Gina24\n")); + dev_dbg(chip->card->dev, "init_hw() - Gina24\n"); if (snd_BUG_ON((subdevice_id & 0xfff0) != GINA24)) return -ENODEV; if ((err = init_dsp_comm_page(chip))) { - DE_INIT(("init_hw - could not initialize DSP comm page\n")); + dev_err(chip->card->dev, + "init_hw - could not initialize DSP comm page\n"); return err; } @@ -78,7 +79,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - DE_INIT(("init_hw done\n")); + dev_dbg(chip->card->dev, "init_hw done\n"); return err; } @@ -155,7 +156,7 @@ static int load_asic(struct echoaudio *chip) control_reg = GML_CONVERTER_ENABLE | GML_48KHZ; err = write_control_reg(chip, control_reg, TRUE); } - DE_INIT(("load_asic() done\n")); + dev_dbg(chip->card->dev, "load_asic() done\n"); return err; } @@ -171,8 +172,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate) /* Only set the clock for internal mode. */ if (chip->input_clock != ECHO_CLOCK_INTERNAL) { - DE_ACT(("set_sample_rate: Cannot set sample rate - " - "clock not set to CLK_CLOCKININTERNAL\n")); + dev_warn(chip->card->dev, + "Cannot set sample rate - clock not set to CLK_CLOCKININTERNAL\n"); /* Save the rate anyhow */ chip->comm_page->sample_rate = cpu_to_le32(rate); chip->sample_rate = rate; @@ -217,7 +218,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate) clock = GML_8KHZ; break; default: - DE_ACT(("set_sample_rate: %d invalid!\n", rate)); + dev_err(chip->card->dev, + "set_sample_rate: %d invalid!\n", rate); return -EINVAL; } @@ -225,7 +227,7 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate) chip->comm_page->sample_rate = cpu_to_le32(rate); /* ignored by the DSP */ chip->sample_rate = rate; - DE_ACT(("set_sample_rate: %d clock %d\n", rate, clock)); + dev_dbg(chip->card->dev, "set_sample_rate: %d clock %d\n", rate, clock); return write_control_reg(chip, control_reg, FALSE); } @@ -236,7 +238,7 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) { u32 control_reg, clocks_from_dsp; - DE_ACT(("set_input_clock:\n")); + dev_dbg(chip->card->dev, "set_input_clock:\n"); /* Mask off the clock select bits */ control_reg = le32_to_cpu(chip->comm_page->control_register) & @@ -245,13 +247,13 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) switch (clock) { case ECHO_CLOCK_INTERNAL: - DE_ACT(("Set Gina24 clock to INTERNAL\n")); + dev_dbg(chip->card->dev, "Set Gina24 clock to INTERNAL\n"); chip->input_clock = ECHO_CLOCK_INTERNAL; return set_sample_rate(chip, chip->sample_rate); case ECHO_CLOCK_SPDIF: if (chip->digital_mode == DIGITAL_MODE_ADAT) return -EAGAIN; - DE_ACT(("Set Gina24 clock to SPDIF\n")); + dev_dbg(chip->card->dev, "Set Gina24 clock to SPDIF\n"); control_reg |= GML_SPDIF_CLOCK; if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_SPDIF96) control_reg |= GML_DOUBLE_SPEED_MODE; @@ -261,21 +263,22 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) case ECHO_CLOCK_ADAT: if (chip->digital_mode != DIGITAL_MODE_ADAT) return -EAGAIN; - DE_ACT(("Set Gina24 clock to ADAT\n")); + dev_dbg(chip->card->dev, "Set Gina24 clock to ADAT\n"); control_reg |= GML_ADAT_CLOCK; control_reg &= ~GML_DOUBLE_SPEED_MODE; break; case ECHO_CLOCK_ESYNC: - DE_ACT(("Set Gina24 clock to ESYNC\n")); + dev_dbg(chip->card->dev, "Set Gina24 clock to ESYNC\n"); control_reg |= GML_ESYNC_CLOCK; control_reg &= ~GML_DOUBLE_SPEED_MODE; break; case ECHO_CLOCK_ESYNC96: - DE_ACT(("Set Gina24 clock to ESYNC96\n")); + dev_dbg(chip->card->dev, "Set Gina24 clock to ESYNC96\n"); control_reg |= GML_ESYNC_CLOCK | GML_DOUBLE_SPEED_MODE; break; default: - DE_ACT(("Input clock 0x%x not supported for Gina24\n", clock)); + dev_err(chip->card->dev, + "Input clock 0x%x not supported for Gina24\n", clock); return -EINVAL; } @@ -304,7 +307,8 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode) incompatible_clock = TRUE; break; default: - DE_ACT(("Digital mode not supported: %d\n", mode)); + dev_err(chip->card->dev, + "Digital mode not supported: %d\n", mode); return -EINVAL; } @@ -344,6 +348,7 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode) return err; chip->digital_mode = mode; - DE_ACT(("set_digital_mode to %d\n", chip->digital_mode)); + dev_dbg(chip->card->dev, + "set_digital_mode to %d\n", chip->digital_mode); return incompatible_clock; } diff --git a/sound/pci/echoaudio/indigo_dsp.c b/sound/pci/echoaudio/indigo_dsp.c index 5e85f14fe5a8..cdeb073fad85 100644 --- a/sound/pci/echoaudio/indigo_dsp.c +++ b/sound/pci/echoaudio/indigo_dsp.c @@ -38,12 +38,13 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) { int err; - DE_INIT(("init_hw() - Indigo\n")); + dev_dbg(chip->card->dev, "init_hw() - Indigo\n"); if (snd_BUG_ON((subdevice_id & 0xfff0) != INDIGO)) return -ENODEV; if ((err = init_dsp_comm_page(chip))) { - DE_INIT(("init_hw - could not initialize DSP comm page\n")); + dev_err(chip->card->dev, + "init_hw - could not initialize DSP comm page\n"); return err; } @@ -60,7 +61,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - DE_INIT(("init_hw done\n")); + dev_dbg(chip->card->dev, "init_hw done\n"); return err; } @@ -109,7 +110,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate) control_reg = MIA_32000; break; default: - DE_ACT(("set_sample_rate: %d invalid!\n", rate)); + dev_err(chip->card->dev, + "set_sample_rate: %d invalid!\n", rate); return -EINVAL; } @@ -147,7 +149,8 @@ static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe, index = output * num_pipes_out(chip) + pipe; chip->comm_page->vmixer[index] = gain; - DE_ACT(("set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain)); + dev_dbg(chip->card->dev, + "set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain); return 0; } diff --git a/sound/pci/echoaudio/indigo_express_dsp.c b/sound/pci/echoaudio/indigo_express_dsp.c index 2e4ab3e34a74..ceda2d7046ac 100644 --- a/sound/pci/echoaudio/indigo_express_dsp.c +++ b/sound/pci/echoaudio/indigo_express_dsp.c @@ -61,7 +61,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate) control_reg |= clock; if (control_reg != old_control_reg) { - DE_ACT(("set_sample_rate: %d clock %d\n", rate, clock)); + dev_dbg(chip->card->dev, + "set_sample_rate: %d clock %d\n", rate, clock); chip->comm_page->control_register = cpu_to_le32(control_reg); chip->sample_rate = rate; clear_handshake(chip); @@ -89,7 +90,8 @@ static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe, index = output * num_pipes_out(chip) + pipe; chip->comm_page->vmixer[index] = gain; - DE_ACT(("set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain)); + dev_dbg(chip->card->dev, + "set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain); return 0; } diff --git a/sound/pci/echoaudio/indigodj_dsp.c b/sound/pci/echoaudio/indigodj_dsp.c index 68f3c8ccc1bf..133915ca6438 100644 --- a/sound/pci/echoaudio/indigodj_dsp.c +++ b/sound/pci/echoaudio/indigodj_dsp.c @@ -38,12 +38,13 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) { int err; - DE_INIT(("init_hw() - Indigo DJ\n")); + dev_dbg(chip->card->dev, "init_hw() - Indigo DJ\n"); if (snd_BUG_ON((subdevice_id & 0xfff0) != INDIGO_DJ)) return -ENODEV; if ((err = init_dsp_comm_page(chip))) { - DE_INIT(("init_hw - could not initialize DSP comm page\n")); + dev_err(chip->card->dev, + "init_hw - could not initialize DSP comm page\n"); return err; } @@ -60,7 +61,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - DE_INIT(("init_hw done\n")); + dev_dbg(chip->card->dev, "init_hw done\n"); return err; } @@ -109,7 +110,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate) control_reg = MIA_32000; break; default: - DE_ACT(("set_sample_rate: %d invalid!\n", rate)); + dev_err(chip->card->dev, + "set_sample_rate: %d invalid!\n", rate); return -EINVAL; } @@ -147,7 +149,8 @@ static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe, index = output * num_pipes_out(chip) + pipe; chip->comm_page->vmixer[index] = gain; - DE_ACT(("set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain)); + dev_dbg(chip->card->dev, + "set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain); return 0; } diff --git a/sound/pci/echoaudio/indigodjx_dsp.c b/sound/pci/echoaudio/indigodjx_dsp.c index bb9632c752a9..26cdfcfc5553 100644 --- a/sound/pci/echoaudio/indigodjx_dsp.c +++ b/sound/pci/echoaudio/indigodjx_dsp.c @@ -35,13 +35,14 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) { int err; - DE_INIT(("init_hw() - Indigo DJx\n")); + dev_dbg(chip->card->dev, "init_hw() - Indigo DJx\n"); if (snd_BUG_ON((subdevice_id & 0xfff0) != INDIGO_DJX)) return -ENODEV; err = init_dsp_comm_page(chip); if (err < 0) { - DE_INIT(("init_hw - could not initialize DSP comm page\n")); + dev_err(chip->card->dev, + "init_hw - could not initialize DSP comm page\n"); return err; } @@ -59,7 +60,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - DE_INIT(("init_hw done\n")); + dev_dbg(chip->card->dev, "init_hw done\n"); return err; } diff --git a/sound/pci/echoaudio/indigoio_dsp.c b/sound/pci/echoaudio/indigoio_dsp.c index beb9a5b69892..5e6df7c25055 100644 --- a/sound/pci/echoaudio/indigoio_dsp.c +++ b/sound/pci/echoaudio/indigoio_dsp.c @@ -38,12 +38,13 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) { int err; - DE_INIT(("init_hw() - Indigo IO\n")); + dev_dbg(chip->card->dev, "init_hw() - Indigo IO\n"); if (snd_BUG_ON((subdevice_id & 0xfff0) != INDIGO_IO)) return -ENODEV; if ((err = init_dsp_comm_page(chip))) { - DE_INIT(("init_hw - could not initialize DSP comm page\n")); + dev_err(chip->card->dev, + "init_hw - could not initialize DSP comm page\n"); return err; } @@ -60,7 +61,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - DE_INIT(("init_hw done\n")); + dev_dbg(chip->card->dev, "init_hw done\n"); return err; } @@ -118,7 +119,8 @@ static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe, index = output * num_pipes_out(chip) + pipe; chip->comm_page->vmixer[index] = gain; - DE_ACT(("set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain)); + dev_dbg(chip->card->dev, + "set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain); return 0; } diff --git a/sound/pci/echoaudio/indigoiox_dsp.c b/sound/pci/echoaudio/indigoiox_dsp.c index 394c6e76bcbc..90cdd271d9fc 100644 --- a/sound/pci/echoaudio/indigoiox_dsp.c +++ b/sound/pci/echoaudio/indigoiox_dsp.c @@ -35,13 +35,14 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) { int err; - DE_INIT(("init_hw() - Indigo IOx\n")); + dev_dbg(chip->card->dev, "init_hw() - Indigo IOx\n"); if (snd_BUG_ON((subdevice_id & 0xfff0) != INDIGO_IOX)) return -ENODEV; err = init_dsp_comm_page(chip); if (err < 0) { - DE_INIT(("init_hw - could not initialize DSP comm page\n")); + dev_err(chip->card->dev, + "init_hw - could not initialize DSP comm page\n"); return err; } @@ -59,7 +60,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - DE_INIT(("init_hw done\n")); + dev_dbg(chip->card->dev, "init_hw done\n"); return err; } diff --git a/sound/pci/echoaudio/layla20_dsp.c b/sound/pci/echoaudio/layla20_dsp.c index 53ce94605044..7f0f6ea08ca7 100644 --- a/sound/pci/echoaudio/layla20_dsp.c +++ b/sound/pci/echoaudio/layla20_dsp.c @@ -40,12 +40,13 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) { int err; - DE_INIT(("init_hw() - Layla20\n")); + dev_dbg(chip->card->dev, "init_hw() - Layla20\n"); if (snd_BUG_ON((subdevice_id & 0xfff0) != LAYLA20)) return -ENODEV; if ((err = init_dsp_comm_page(chip))) { - DE_INIT(("init_hw - could not initialize DSP comm page\n")); + dev_err(chip->card->dev, + "init_hw - could not initialize DSP comm page\n"); return err; } @@ -64,7 +65,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - DE_INIT(("init_hw done\n")); + dev_dbg(chip->card->dev, "init_hw done\n"); return err; } @@ -121,7 +122,8 @@ static int check_asic_status(struct echoaudio *chip) /* The DSP will return a value to indicate whether or not the ASIC is currently loaded */ if (read_dsp(chip, &asic_status) < 0) { - DE_ACT(("check_asic_status: failed on read_dsp\n")); + dev_err(chip->card->dev, + "check_asic_status: failed on read_dsp\n"); return -EIO; } @@ -164,8 +166,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate) /* Only set the clock for internal mode. Do not return failure, simply treat it as a non-event. */ if (chip->input_clock != ECHO_CLOCK_INTERNAL) { - DE_ACT(("set_sample_rate: Cannot set sample rate - " - "clock not set to CLK_CLOCKININTERNAL\n")); + dev_warn(chip->card->dev, + "Cannot set sample rate - clock not set to CLK_CLOCKININTERNAL\n"); chip->comm_page->sample_rate = cpu_to_le32(rate); chip->sample_rate = rate; return 0; @@ -174,7 +176,7 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate) if (wait_handshake(chip)) return -EIO; - DE_ACT(("set_sample_rate(%d)\n", rate)); + dev_dbg(chip->card->dev, "set_sample_rate(%d)\n", rate); chip->sample_rate = rate; chip->comm_page->sample_rate = cpu_to_le32(rate); clear_handshake(chip); @@ -188,29 +190,30 @@ static int set_input_clock(struct echoaudio *chip, u16 clock_source) u16 clock; u32 rate; - DE_ACT(("set_input_clock:\n")); + dev_dbg(chip->card->dev, "set_input_clock:\n"); rate = 0; switch (clock_source) { case ECHO_CLOCK_INTERNAL: - DE_ACT(("Set Layla20 clock to INTERNAL\n")); + dev_dbg(chip->card->dev, "Set Layla20 clock to INTERNAL\n"); rate = chip->sample_rate; clock = LAYLA20_CLOCK_INTERNAL; break; case ECHO_CLOCK_SPDIF: - DE_ACT(("Set Layla20 clock to SPDIF\n")); + dev_dbg(chip->card->dev, "Set Layla20 clock to SPDIF\n"); clock = LAYLA20_CLOCK_SPDIF; break; case ECHO_CLOCK_WORD: - DE_ACT(("Set Layla20 clock to WORD\n")); + dev_dbg(chip->card->dev, "Set Layla20 clock to WORD\n"); clock = LAYLA20_CLOCK_WORD; break; case ECHO_CLOCK_SUPER: - DE_ACT(("Set Layla20 clock to SUPER\n")); + dev_dbg(chip->card->dev, "Set Layla20 clock to SUPER\n"); clock = LAYLA20_CLOCK_SUPER; break; default: - DE_ACT(("Input clock 0x%x not supported for Layla24\n", - clock_source)); + dev_err(chip->card->dev, + "Input clock 0x%x not supported for Layla24\n", + clock_source); return -EINVAL; } chip->input_clock = clock_source; @@ -229,7 +232,7 @@ static int set_input_clock(struct echoaudio *chip, u16 clock_source) static int set_output_clock(struct echoaudio *chip, u16 clock) { - DE_ACT(("set_output_clock: %d\n", clock)); + dev_dbg(chip->card->dev, "set_output_clock: %d\n", clock); switch (clock) { case ECHO_CLOCK_SUPER: clock = LAYLA20_OUTPUT_CLOCK_SUPER; @@ -238,7 +241,7 @@ static int set_output_clock(struct echoaudio *chip, u16 clock) clock = LAYLA20_OUTPUT_CLOCK_WORD; break; default: - DE_ACT(("set_output_clock wrong clock\n")); + dev_err(chip->card->dev, "set_output_clock wrong clock\n"); return -EINVAL; } @@ -283,7 +286,7 @@ static int update_flags(struct echoaudio *chip) static int set_professional_spdif(struct echoaudio *chip, char prof) { - DE_ACT(("set_professional_spdif %d\n", prof)); + dev_dbg(chip->card->dev, "set_professional_spdif %d\n", prof); if (prof) chip->comm_page->flags |= cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF); diff --git a/sound/pci/echoaudio/layla24_dsp.c b/sound/pci/echoaudio/layla24_dsp.c index 8c041647f285..eb8f218f79fe 100644 --- a/sound/pci/echoaudio/layla24_dsp.c +++ b/sound/pci/echoaudio/layla24_dsp.c @@ -40,12 +40,13 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) { int err; - DE_INIT(("init_hw() - Layla24\n")); + dev_dbg(chip->card->dev, "init_hw() - Layla24\n"); if (snd_BUG_ON((subdevice_id & 0xfff0) != LAYLA24)) return -ENODEV; if ((err = init_dsp_comm_page(chip))) { - DE_INIT(("init_hw - could not initialize DSP comm page\n")); + dev_err(chip->card->dev, + "init_hw - could not initialize DSP comm page\n"); return err; } @@ -69,7 +70,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) if ((err = init_line_levels(chip)) < 0) return err; - DE_INIT(("init_hw done\n")); + dev_dbg(chip->card->dev, "init_hw done\n"); return err; } @@ -117,7 +118,7 @@ static int load_asic(struct echoaudio *chip) if (chip->asic_loaded) return 1; - DE_INIT(("load_asic\n")); + dev_dbg(chip->card->dev, "load_asic\n"); /* Give the DSP a few milliseconds to settle down */ mdelay(10); @@ -151,7 +152,7 @@ static int load_asic(struct echoaudio *chip) err = write_control_reg(chip, GML_CONVERTER_ENABLE | GML_48KHZ, TRUE); - DE_INIT(("load_asic() done\n")); + dev_dbg(chip->card->dev, "load_asic() done\n"); return err; } @@ -167,8 +168,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate) /* Only set the clock for internal mode. */ if (chip->input_clock != ECHO_CLOCK_INTERNAL) { - DE_ACT(("set_sample_rate: Cannot set sample rate - " - "clock not set to CLK_CLOCKININTERNAL\n")); + dev_warn(chip->card->dev, + "Cannot set sample rate - clock not set to CLK_CLOCKININTERNAL\n"); /* Save the rate anyhow */ chip->comm_page->sample_rate = cpu_to_le32(rate); chip->sample_rate = rate; @@ -241,7 +242,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate) chip->comm_page->sample_rate = cpu_to_le32(rate); /* ignored by the DSP ? */ chip->sample_rate = rate; - DE_ACT(("set_sample_rate: %d clock %d\n", rate, control_reg)); + dev_dbg(chip->card->dev, + "set_sample_rate: %d clock %d\n", rate, control_reg); return write_control_reg(chip, control_reg, FALSE); } @@ -260,7 +262,7 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) /* Pick the new clock */ switch (clock) { case ECHO_CLOCK_INTERNAL: - DE_ACT(("Set Layla24 clock to INTERNAL\n")); + dev_dbg(chip->card->dev, "Set Layla24 clock to INTERNAL\n"); chip->input_clock = ECHO_CLOCK_INTERNAL; return set_sample_rate(chip, chip->sample_rate); case ECHO_CLOCK_SPDIF: @@ -269,7 +271,7 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) control_reg |= GML_SPDIF_CLOCK; /* Layla24 doesn't support 96KHz S/PDIF */ control_reg &= ~GML_DOUBLE_SPEED_MODE; - DE_ACT(("Set Layla24 clock to SPDIF\n")); + dev_dbg(chip->card->dev, "Set Layla24 clock to SPDIF\n"); break; case ECHO_CLOCK_WORD: control_reg |= GML_WORD_CLOCK; @@ -277,17 +279,18 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) control_reg |= GML_DOUBLE_SPEED_MODE; else control_reg &= ~GML_DOUBLE_SPEED_MODE; - DE_ACT(("Set Layla24 clock to WORD\n")); + dev_dbg(chip->card->dev, "Set Layla24 clock to WORD\n"); break; case ECHO_CLOCK_ADAT: if (chip->digital_mode != DIGITAL_MODE_ADAT) return -EAGAIN; control_reg |= GML_ADAT_CLOCK; control_reg &= ~GML_DOUBLE_SPEED_MODE; - DE_ACT(("Set Layla24 clock to ADAT\n")); + dev_dbg(chip->card->dev, "Set Layla24 clock to ADAT\n"); break; default: - DE_ACT(("Input clock 0x%x not supported for Layla24\n", clock)); + dev_err(chip->card->dev, + "Input clock 0x%x not supported for Layla24\n", clock); return -EINVAL; } @@ -353,7 +356,8 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode) asic = FW_LAYLA24_2A_ASIC; break; default: - DE_ACT(("Digital mode not supported: %d\n", mode)); + dev_err(chip->card->dev, + "Digital mode not supported: %d\n", mode); return -EINVAL; } @@ -393,6 +397,6 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode) return err; chip->digital_mode = mode; - DE_ACT(("set_digital_mode to %d\n", mode)); + dev_dbg(chip->card->dev, "set_digital_mode to %d\n", mode); return incompatible_clock; } diff --git a/sound/pci/echoaudio/mia_dsp.c b/sound/pci/echoaudio/mia_dsp.c index 6ebfa6e7ab9e..ed2f21dcd1c9 100644 --- a/sound/pci/echoaudio/mia_dsp.c +++ b/sound/pci/echoaudio/mia_dsp.c @@ -41,12 +41,13 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) { int err; - DE_INIT(("init_hw() - Mia\n")); + dev_dbg(chip->card->dev, "init_hw() - Mia\n"); if (snd_BUG_ON((subdevice_id & 0xfff0) != MIA)) return -ENODEV; if ((err = init_dsp_comm_page(chip))) { - DE_INIT(("init_hw - could not initialize DSP comm page\n")); + dev_err(chip->card->dev, + "init_hw - could not initialize DSP comm page\n"); return err; } @@ -66,7 +67,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - DE_INIT(("init_hw done\n")); + dev_dbg(chip->card->dev, "init_hw done\n"); return err; } @@ -126,7 +127,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate) control_reg = MIA_32000; break; default: - DE_ACT(("set_sample_rate: %d invalid!\n", rate)); + dev_err(chip->card->dev, + "set_sample_rate: %d invalid!\n", rate); return -EINVAL; } @@ -153,7 +155,7 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate) static int set_input_clock(struct echoaudio *chip, u16 clock) { - DE_ACT(("set_input_clock(%d)\n", clock)); + dev_dbg(chip->card->dev, "set_input_clock(%d)\n", clock); if (snd_BUG_ON(clock != ECHO_CLOCK_INTERNAL && clock != ECHO_CLOCK_SPDIF)) return -EINVAL; @@ -181,7 +183,8 @@ static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe, index = output * num_pipes_out(chip) + pipe; chip->comm_page->vmixer[index] = gain; - DE_ACT(("set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain)); + dev_dbg(chip->card->dev, + "set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain); return 0; } @@ -211,7 +214,7 @@ static int update_flags(struct echoaudio *chip) static int set_professional_spdif(struct echoaudio *chip, char prof) { - DE_ACT(("set_professional_spdif %d\n", prof)); + dev_dbg(chip->card->dev, "set_professional_spdif %d\n", prof); if (prof) chip->comm_page->flags |= cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF); diff --git a/sound/pci/echoaudio/midi.c b/sound/pci/echoaudio/midi.c index 7f4dfae0323a..8d43c5a4976b 100644 --- a/sound/pci/echoaudio/midi.c +++ b/sound/pci/echoaudio/midi.c @@ -36,7 +36,7 @@ /* Start and stop Midi input */ static int enable_midi_input(struct echoaudio *chip, char enable) { - DE_MID(("enable_midi_input(%d)\n", enable)); + dev_dbg(chip->card->dev, "enable_midi_input(%d)\n", enable); if (wait_handshake(chip)) return -EIO; @@ -74,7 +74,7 @@ static int write_midi(struct echoaudio *chip, u8 *data, int bytes) chip->comm_page->midi_out_free_count = 0; clear_handshake(chip); send_vector(chip, DSP_VC_MIDI_WRITE); - DE_MID(("write_midi: %d\n", bytes)); + dev_dbg(chip->card->dev, "write_midi: %d\n", bytes); return bytes; } @@ -157,7 +157,7 @@ static int snd_echo_midi_input_open(struct snd_rawmidi_substream *substream) struct echoaudio *chip = substream->rmidi->private_data; chip->midi_in = substream; - DE_MID(("rawmidi_iopen\n")); + dev_dbg(chip->card->dev, "rawmidi_iopen\n"); return 0; } @@ -183,7 +183,7 @@ static int snd_echo_midi_input_close(struct snd_rawmidi_substream *substream) struct echoaudio *chip = substream->rmidi->private_data; chip->midi_in = NULL; - DE_MID(("rawmidi_iclose\n")); + dev_dbg(chip->card->dev, "rawmidi_iclose\n"); return 0; } @@ -196,7 +196,7 @@ static int snd_echo_midi_output_open(struct snd_rawmidi_substream *substream) chip->tinuse = 0; chip->midi_full = 0; chip->midi_out = substream; - DE_MID(("rawmidi_oopen\n")); + dev_dbg(chip->card->dev, "rawmidi_open\n"); return 0; } @@ -209,7 +209,7 @@ static void snd_echo_midi_output_write(unsigned long data) int bytes, sent, time; unsigned char buf[MIDI_OUT_BUFFER_SIZE - 1]; - DE_MID(("snd_echo_midi_output_write\n")); + dev_dbg(chip->card->dev, "snd_echo_midi_output_write\n"); /* No interrupts are involved: we have to check at regular intervals if the card's output buffer has room for new data. */ sent = bytes = 0; @@ -218,7 +218,7 @@ static void snd_echo_midi_output_write(unsigned long data) if (!snd_rawmidi_transmit_empty(chip->midi_out)) { bytes = snd_rawmidi_transmit_peek(chip->midi_out, buf, MIDI_OUT_BUFFER_SIZE - 1); - DE_MID(("Try to send %d bytes...\n", bytes)); + dev_dbg(chip->card->dev, "Try to send %d bytes...\n", bytes); sent = write_midi(chip, buf, bytes); if (sent < 0) { dev_err(chip->card->dev, @@ -227,12 +227,12 @@ static void snd_echo_midi_output_write(unsigned long data) sent = 9000; chip->midi_full = 1; } else if (sent > 0) { - DE_MID(("%d bytes sent\n", sent)); + dev_dbg(chip->card->dev, "%d bytes sent\n", sent); snd_rawmidi_transmit_ack(chip->midi_out, sent); } else { /* Buffer is full. DSP's internal buffer is 64 (128 ?) bytes long. Let's wait until half of them are sent */ - DE_MID(("Full\n")); + dev_dbg(chip->card->dev, "Full\n"); sent = 32; chip->midi_full = 1; } @@ -244,7 +244,8 @@ static void snd_echo_midi_output_write(unsigned long data) sent */ time = (sent << 3) / 25 + 1; /* 8/25=0.32ms to send a byte */ mod_timer(&chip->timer, jiffies + (time * HZ + 999) / 1000); - DE_MID(("Timer armed(%d)\n", ((time * HZ + 999) / 1000))); + dev_dbg(chip->card->dev, + "Timer armed(%d)\n", ((time * HZ + 999) / 1000)); } spin_unlock_irqrestore(&chip->lock, flags); } @@ -256,7 +257,7 @@ static void snd_echo_midi_output_trigger(struct snd_rawmidi_substream *substream { struct echoaudio *chip = substream->rmidi->private_data; - DE_MID(("snd_echo_midi_output_trigger(%d)\n", up)); + dev_dbg(chip->card->dev, "snd_echo_midi_output_trigger(%d)\n", up); spin_lock_irq(&chip->lock); if (up) { if (!chip->tinuse) { @@ -270,7 +271,7 @@ static void snd_echo_midi_output_trigger(struct snd_rawmidi_substream *substream chip->tinuse = 0; spin_unlock_irq(&chip->lock); del_timer_sync(&chip->timer); - DE_MID(("Timer removed\n")); + dev_dbg(chip->card->dev, "Timer removed\n"); return; } } @@ -287,7 +288,7 @@ static int snd_echo_midi_output_close(struct snd_rawmidi_substream *substream) struct echoaudio *chip = substream->rmidi->private_data; chip->midi_out = NULL; - DE_MID(("rawmidi_oclose\n")); + dev_dbg(chip->card->dev, "rawmidi_oclose\n"); return 0; } @@ -327,6 +328,6 @@ static int snd_echo_midi_create(struct snd_card *card, chip->rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; - DE_INIT(("MIDI ok\n")); + dev_dbg(chip->card->dev, "MIDI ok\n"); return 0; } diff --git a/sound/pci/echoaudio/mona_dsp.c b/sound/pci/echoaudio/mona_dsp.c index 6e6a7eb555b8..cc46a8c8e3dd 100644 --- a/sound/pci/echoaudio/mona_dsp.c +++ b/sound/pci/echoaudio/mona_dsp.c @@ -41,12 +41,13 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) { int err; - DE_INIT(("init_hw() - Mona\n")); + dev_dbg(chip->card->dev, "init_hw() - Mona\n"); if (snd_BUG_ON((subdevice_id & 0xfff0) != MONA)) return -ENODEV; if ((err = init_dsp_comm_page(chip))) { - DE_INIT(("init_hw - could not initialize DSP comm page\n")); + dev_err(chip->card->dev, + "init_hw - could not initialize DSP comm page\n"); return err; } @@ -71,7 +72,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - DE_INIT(("init_hw done\n")); + dev_dbg(chip->card->dev, "init_hw done\n"); return err; } @@ -202,8 +203,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate) /* Only set the clock for internal mode. */ if (chip->input_clock != ECHO_CLOCK_INTERNAL) { - DE_ACT(("set_sample_rate: Cannot set sample rate - " - "clock not set to CLK_CLOCKININTERNAL\n")); + dev_dbg(chip->card->dev, + "Cannot set sample rate - clock not set to CLK_CLOCKININTERNAL\n"); /* Save the rate anyhow */ chip->comm_page->sample_rate = cpu_to_le32(rate); chip->sample_rate = rate; @@ -279,7 +280,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate) clock = GML_8KHZ; break; default: - DE_ACT(("set_sample_rate: %d invalid!\n", rate)); + dev_err(chip->card->dev, + "set_sample_rate: %d invalid!\n", rate); return -EINVAL; } @@ -287,7 +289,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate) chip->comm_page->sample_rate = cpu_to_le32(rate); /* ignored by the DSP */ chip->sample_rate = rate; - DE_ACT(("set_sample_rate: %d clock %d\n", rate, clock)); + dev_dbg(chip->card->dev, + "set_sample_rate: %d clock %d\n", rate, clock); return write_control_reg(chip, control_reg, force_write); } @@ -299,7 +302,7 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) u32 control_reg, clocks_from_dsp; int err; - DE_ACT(("set_input_clock:\n")); + dev_dbg(chip->card->dev, "set_input_clock:\n"); /* Prevent two simultaneous calls to switch_asic() */ if (atomic_read(&chip->opencount)) @@ -312,7 +315,7 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) switch (clock) { case ECHO_CLOCK_INTERNAL: - DE_ACT(("Set Mona clock to INTERNAL\n")); + dev_dbg(chip->card->dev, "Set Mona clock to INTERNAL\n"); chip->input_clock = ECHO_CLOCK_INTERNAL; return set_sample_rate(chip, chip->sample_rate); case ECHO_CLOCK_SPDIF: @@ -324,7 +327,7 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) spin_lock_irq(&chip->lock); if (err < 0) return err; - DE_ACT(("Set Mona clock to SPDIF\n")); + dev_dbg(chip->card->dev, "Set Mona clock to SPDIF\n"); control_reg |= GML_SPDIF_CLOCK; if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_SPDIF96) control_reg |= GML_DOUBLE_SPEED_MODE; @@ -332,7 +335,7 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) control_reg &= ~GML_DOUBLE_SPEED_MODE; break; case ECHO_CLOCK_WORD: - DE_ACT(("Set Mona clock to WORD\n")); + dev_dbg(chip->card->dev, "Set Mona clock to WORD\n"); spin_unlock_irq(&chip->lock); err = switch_asic(chip, clocks_from_dsp & GML_CLOCK_DETECT_BIT_WORD96); @@ -346,14 +349,15 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) control_reg &= ~GML_DOUBLE_SPEED_MODE; break; case ECHO_CLOCK_ADAT: - DE_ACT(("Set Mona clock to ADAT\n")); + dev_dbg(chip->card->dev, "Set Mona clock to ADAT\n"); if (chip->digital_mode != DIGITAL_MODE_ADAT) return -EAGAIN; control_reg |= GML_ADAT_CLOCK; control_reg &= ~GML_DOUBLE_SPEED_MODE; break; default: - DE_ACT(("Input clock 0x%x not supported for Mona\n", clock)); + dev_err(chip->card->dev, + "Input clock 0x%x not supported for Mona\n", clock); return -EINVAL; } @@ -381,7 +385,8 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode) incompatible_clock = TRUE; break; default: - DE_ACT(("Digital mode not supported: %d\n", mode)); + dev_err(chip->card->dev, + "Digital mode not supported: %d\n", mode); return -EINVAL; } @@ -422,6 +427,6 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode) return err; chip->digital_mode = mode; - DE_ACT(("set_digital_mode to %d\n", mode)); + dev_dbg(chip->card->dev, "set_digital_mode to %d\n", mode); return incompatible_clock; } -- cgit v1.2.3 From 31604d35db18c1382c7ee9fa836ff9ab0b4d2751 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 3 Nov 2014 14:54:36 +0100 Subject: ALSA: emu10k1: Deletion of unnecessary checks before three function calls The functions kfree(), release_firmware() and snd_util_memhdr_free() test whether their argument is NULL and then return immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emu10k1_main.c | 9 +++------ sound/pci/emu10k1/emufx.c | 3 +-- 2 files changed, 4 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 229269788023..b4458a630a7c 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -1289,10 +1289,8 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu) } if (emu->emu1010.firmware_thread) kthread_stop(emu->emu1010.firmware_thread); - if (emu->firmware) - release_firmware(emu->firmware); - if (emu->dock_fw) - release_firmware(emu->dock_fw); + release_firmware(emu->firmware); + release_firmware(emu->dock_fw); if (emu->irq >= 0) free_irq(emu->irq, emu); /* remove reserved page */ @@ -1301,8 +1299,7 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu) (struct snd_util_memblk *)emu->reserved_page); emu->reserved_page = NULL; } - if (emu->memhdr) - snd_util_memhdr_free(emu->memhdr); + snd_util_memhdr_free(emu->memhdr); if (emu->silent_page.area) snd_dma_free_pages(&emu->silent_page); if (emu->ptb_pages.area) diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index 745f0627c634..eb5c0aba41c1 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -777,8 +777,7 @@ static void snd_emu10k1_ctl_private_free(struct snd_kcontrol *kctl) kctl->private_value = 0; list_del(&ctl->list); kfree(ctl); - if (kctl->tlv.p) - kfree(kctl->tlv.p); + kfree(kctl->tlv.p); } static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu, -- cgit v1.2.3 From 2603fe21b764eb7412598c8c6cd6199fb8b1d9c5 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Mon, 3 Nov 2014 21:35:48 +0100 Subject: ALSA: es18xx: Add GPO controls Add GPO0 and GPO1 (General Purpose Outputs) controls to mixer. These can be used on some cards to control amplifier mute (seen in ES1868 datasheet) or additional onboard chips such as QX2130 QXpander processor. These GPOs are present on ES1868, ES1869, ES1887 and ES1888 chips. Tested on ES1868 with QX2130. Signed-off-by: Ondrej Zary Signed-off-by: Takashi Iwai --- sound/isa/es18xx.c | 52 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index 63e7323e218f..b481bb8c31bc 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c @@ -156,6 +156,7 @@ struct snd_es18xx { #define ES18XX_I2S 0x0200 /* I2S mixer control */ #define ES18XX_MUTEREC 0x0400 /* Record source can be muted */ #define ES18XX_CONTROL 0x0800 /* Has control ports */ +#define ES18XX_GPO_2BIT 0x1000 /* GPO0,1 controlled by PM port */ /* Power Management */ #define ES18XX_PM 0x07 @@ -1120,11 +1121,14 @@ static int snd_es18xx_reg_read(struct snd_es18xx *chip, unsigned char reg) return snd_es18xx_read(chip, reg); } -#define ES18XX_SINGLE(xname, xindex, reg, shift, mask, invert) \ +#define ES18XX_SINGLE(xname, xindex, reg, shift, mask, flags) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ .info = snd_es18xx_info_single, \ .get = snd_es18xx_get_single, .put = snd_es18xx_put_single, \ - .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) } + .private_value = reg | (shift << 8) | (mask << 16) | (flags << 24) } + +#define ES18XX_FL_INVERT (1 << 0) +#define ES18XX_FL_PMPORT (1 << 1) static int snd_es18xx_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -1143,10 +1147,14 @@ static int snd_es18xx_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e int reg = kcontrol->private_value & 0xff; int shift = (kcontrol->private_value >> 8) & 0xff; int mask = (kcontrol->private_value >> 16) & 0xff; - int invert = (kcontrol->private_value >> 24) & 0xff; + int invert = (kcontrol->private_value >> 24) & ES18XX_FL_INVERT; + int pm_port = (kcontrol->private_value >> 24) & ES18XX_FL_PMPORT; int val; - - val = snd_es18xx_reg_read(chip, reg); + + if (pm_port) + val = inb(chip->port + ES18XX_PM); + else + val = snd_es18xx_reg_read(chip, reg); ucontrol->value.integer.value[0] = (val >> shift) & mask; if (invert) ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; @@ -1159,7 +1167,8 @@ static int snd_es18xx_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e int reg = kcontrol->private_value & 0xff; int shift = (kcontrol->private_value >> 8) & 0xff; int mask = (kcontrol->private_value >> 16) & 0xff; - int invert = (kcontrol->private_value >> 24) & 0xff; + int invert = (kcontrol->private_value >> 24) & ES18XX_FL_INVERT; + int pm_port = (kcontrol->private_value >> 24) & ES18XX_FL_PMPORT; unsigned char val; val = (ucontrol->value.integer.value[0] & mask); @@ -1167,6 +1176,15 @@ static int snd_es18xx_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e val = mask - val; mask <<= shift; val <<= shift; + if (pm_port) { + unsigned char cur = inb(chip->port + ES18XX_PM); + + if ((cur & mask) == val) + return 0; + outb((cur & ~mask) | val, chip->port + ES18XX_PM); + return 1; + } + return snd_es18xx_reg_bits(chip, reg, mask, val) != val; } @@ -1288,7 +1306,7 @@ static struct snd_kcontrol_new snd_es18xx_opt_speaker = ES18XX_SINGLE("Beep Playback Volume", 0, 0x3c, 0, 7, 0); static struct snd_kcontrol_new snd_es18xx_opt_1869[] = { -ES18XX_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1), +ES18XX_SINGLE("Capture Switch", 0, 0x1c, 4, 1, ES18XX_FL_INVERT), ES18XX_SINGLE("Video Playback Switch", 0, 0x7f, 0, 1, 0), ES18XX_DOUBLE("Mono Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0), ES18XX_DOUBLE("Mono Capture Volume", 0, 0x6f, 0x6f, 4, 0, 15, 0) @@ -1347,6 +1365,11 @@ static struct snd_kcontrol_new snd_es18xx_hw_volume_controls[] = { ES18XX_SINGLE("Hardware Master Volume Split", 0, 0x64, 7, 1, 0), }; +static struct snd_kcontrol_new snd_es18xx_opt_gpo_2bit[] = { +ES18XX_SINGLE("GPO0 Switch", 0, ES18XX_PM, 0, 1, ES18XX_FL_PMPORT), +ES18XX_SINGLE("GPO1 Switch", 0, ES18XX_PM, 1, 1, ES18XX_FL_PMPORT), +}; + static int snd_es18xx_config_read(struct snd_es18xx *chip, unsigned char reg) { int data; @@ -1613,10 +1636,10 @@ static int snd_es18xx_probe(struct snd_es18xx *chip, switch (chip->version) { case 0x1868: - chip->caps = ES18XX_DUPLEX_MONO | ES18XX_DUPLEX_SAME | ES18XX_CONTROL; + chip->caps = ES18XX_DUPLEX_MONO | ES18XX_DUPLEX_SAME | ES18XX_CONTROL | ES18XX_GPO_2BIT; break; case 0x1869: - chip->caps = ES18XX_PCM2 | ES18XX_SPATIALIZER | ES18XX_RECMIX | ES18XX_NEW_RATE | ES18XX_AUXB | ES18XX_MONO | ES18XX_MUTEREC | ES18XX_CONTROL | ES18XX_HWV; + chip->caps = ES18XX_PCM2 | ES18XX_SPATIALIZER | ES18XX_RECMIX | ES18XX_NEW_RATE | ES18XX_AUXB | ES18XX_MONO | ES18XX_MUTEREC | ES18XX_CONTROL | ES18XX_HWV | ES18XX_GPO_2BIT; break; case 0x1878: chip->caps = ES18XX_DUPLEX_MONO | ES18XX_DUPLEX_SAME | ES18XX_I2S | ES18XX_CONTROL; @@ -1626,7 +1649,7 @@ static int snd_es18xx_probe(struct snd_es18xx *chip, break; case 0x1887: case 0x1888: - chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME; + chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME | ES18XX_GPO_2BIT; break; default: snd_printk(KERN_ERR "[0x%lx] unsupported chip ES%x\n", @@ -1928,6 +1951,15 @@ static int snd_es18xx_mixer(struct snd_card *card) return err; } } + if (chip->caps & ES18XX_GPO_2BIT) { + for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_opt_gpo_2bit); idx++) { + err = snd_ctl_add(card, + snd_ctl_new1(&snd_es18xx_opt_gpo_2bit[idx], + chip)); + if (err < 0) + return err; + } + } return 0; } -- cgit v1.2.3 From d507941beb1ef98c19e2902007aee4faf36f854f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 4 Nov 2014 13:57:15 +0100 Subject: ALSA: pcm: Correct PCM BUG error message While converting to dev_*(), the message showing the invalid PCM position was wrongly tagged as if an XRUN although it's actually a BUG. This patch corrects the message again. Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index dfc28542a007..7b9e2fb35a86 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -345,7 +345,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, snd_pcm_debug_name(substream, name, sizeof(name)); xrun_log_show(substream); pcm_err(substream->pcm, - "XRUN: %s, pos = %ld, buffer size = %ld, period size = %ld\n", + "BUG: %s, pos = %ld, buffer size = %ld, period size = %ld\n", name, pos, runtime->buffer_size, runtime->period_size); } -- cgit v1.2.3 From f5914908a5b7b2338f210e56827a1ef35585dc6d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 4 Nov 2014 12:45:59 +0100 Subject: ALSA: pcm: Replace PCM hwptr tracking with tracepoints ALSA PCM core has a mechanism tracking the PCM hwptr updates for analyzing XRUNs. But its log is limited (up to 10) and its log output is a kernel message, which is hard to handle. In this patch, the hwptr logging is moved to the tracing infrastructure instead of its own. Not only the hwptr updates but also XRUN and hwptr errors are recorded on the trace log, so that user can see such events at the exact timing. The new "snd_pcm" entry will appear in the tracing events: # ls -F /sys/kernel/debug/tracing/events/snd_pcm enable filter hw_ptr_error/ hwptr/ xrun/ The hwptr is for the regular hwptr update events. An event trace looks like: aplay-26187 [004] d..3 4012.834761: hwptr: pcmC0D0p/sub0: POS: pos=488, old=0, base=0, period=1024, buf=16384 "POS" shows the hwptr update by the explicit position update call and "IRQ" means the hwptr update by the interrupt, i.e. snd_pcm_period_elapsed() call. The "pos" is the passed ring-buffer offset by the caller, "old" is the previous hwptr, "base" is the hwptr base position, "period" and "buf" are period- and buffer-size of the target PCM substream. (Note that the hwptr position displayed here isn't the ring-buffer offset. It increments up to the PCM position boundary.) The XRUN event appears similarly, but without "pos" field. The hwptr error events appear with the PCM identifier and its reason string, such as "Lost interrupt?". The XRUN and hwptr error reports on kernel message are still left, can be turned on/off via xrun_debug proc like before. But the bit 3, 4, 5 and 6 bits of xrun_debug proc are dropped by this patch. Also, along with the change, the message strings have been reformatted to be a bit more consistent. Last but not least, the hwptr reporting is enabled only when CONFIG_SND_PCM_XRUN_DEBUG is set. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/Procfile.txt | 13 --- sound/core/Makefile | 3 + sound/core/pcm_lib.c | 146 ++++++---------------------------- sound/core/pcm_trace.h | 110 +++++++++++++++++++++++++ 4 files changed, 137 insertions(+), 135 deletions(-) create mode 100644 sound/core/pcm_trace.h (limited to 'sound') diff --git a/Documentation/sound/alsa/Procfile.txt b/Documentation/sound/alsa/Procfile.txt index 7fcd1ad96fcc..cfc49567b9dc 100644 --- a/Documentation/sound/alsa/Procfile.txt +++ b/Documentation/sound/alsa/Procfile.txt @@ -101,10 +101,6 @@ card*/pcm*/xrun_debug bit 0 = Enable XRUN/jiffies debug messages bit 1 = Show stack trace at XRUN / jiffies check bit 2 = Enable additional jiffies check - bit 3 = Log hwptr update at each period interrupt - bit 4 = Log hwptr update at each snd_pcm_update_hw_ptr() - bit 5 = Show last 10 positions on error - bit 6 = Do above only once When the bit 0 is set, the driver will show the messages to kernel log when an xrun is detected. The debug message is @@ -121,15 +117,6 @@ card*/pcm*/xrun_debug buggy) hardware that doesn't give smooth pointer updates. This feature is enabled via the bit 2. - Bits 3 and 4 are for logging the hwptr records. Note that - these will give flood of kernel messages. - - When bit 5 is set, the driver logs the last 10 xrun errors and - the proc file shows each jiffies, position, period_size, - buffer_size, old_hw_ptr, and hw_ptr_base values. - - When bit 6 is set, the full xrun log is shown only once. - card*/pcm*/sub*/info The general information of this PCM sub-stream. diff --git a/sound/core/Makefile b/sound/core/Makefile index 394a38909f6b..4daf2f58261c 100644 --- a/sound/core/Makefile +++ b/sound/core/Makefile @@ -14,6 +14,9 @@ snd-pcm-y := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \ pcm_memory.o memalloc.o snd-pcm-$(CONFIG_SND_DMA_SGBUF) += sgbuf.o +# for trace-points +CFLAGS_pcm_lib.o := -I$(src) + snd-pcm-dmaengine-objs := pcm_dmaengine.o snd-rawmidi-objs := rawmidi.o diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 7b9e2fb35a86..ec9e7866177f 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -32,6 +32,15 @@ #include #include +#ifdef CONFIG_SND_PCM_XRUN_DEBUG +#define CREATE_TRACE_POINTS +#include "pcm_trace.h" +#else +#define trace_hwptr(substream, pos, in_interrupt) +#define trace_xrun(substream) +#define trace_hw_ptr_error(substream, reason) +#endif + /* * fill ring buffer with silence * runtime->silence_start: starting pointer to silence area @@ -146,10 +155,6 @@ EXPORT_SYMBOL(snd_pcm_debug_name); #define XRUN_DEBUG_BASIC (1<<0) #define XRUN_DEBUG_STACK (1<<1) /* dump also stack */ #define XRUN_DEBUG_JIFFIESCHECK (1<<2) /* do jiffies check */ -#define XRUN_DEBUG_PERIODUPDATE (1<<3) /* full period update info */ -#define XRUN_DEBUG_HWPTRUPDATE (1<<4) /* full hwptr update info */ -#define XRUN_DEBUG_LOG (1<<5) /* show last 10 positions on err */ -#define XRUN_DEBUG_LOGONCE (1<<6) /* do above only once */ #ifdef CONFIG_SND_PCM_XRUN_DEBUG @@ -168,6 +173,7 @@ static void xrun(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; + trace_xrun(substream); if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); @@ -180,97 +186,19 @@ static void xrun(struct snd_pcm_substream *substream) } #ifdef CONFIG_SND_PCM_XRUN_DEBUG -#define hw_ptr_error(substream, fmt, args...) \ +#define hw_ptr_error(substream, in_interrupt, reason, fmt, args...) \ do { \ + trace_hw_ptr_error(substream, reason); \ if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { \ - xrun_log_show(substream); \ - pr_err_ratelimited("ALSA: PCM: " fmt, ##args); \ + pr_err_ratelimited("ALSA: PCM: [%c] " reason ": " fmt, \ + (in_interrupt) ? 'Q' : 'P', ##args); \ dump_stack_on_xrun(substream); \ } \ } while (0) -#define XRUN_LOG_CNT 10 - -struct hwptr_log_entry { - unsigned int in_interrupt; - unsigned long jiffies; - snd_pcm_uframes_t pos; - snd_pcm_uframes_t period_size; - snd_pcm_uframes_t buffer_size; - snd_pcm_uframes_t old_hw_ptr; - snd_pcm_uframes_t hw_ptr_base; -}; - -struct snd_pcm_hwptr_log { - unsigned int idx; - unsigned int hit: 1; - struct hwptr_log_entry entries[XRUN_LOG_CNT]; -}; - -static void xrun_log(struct snd_pcm_substream *substream, - snd_pcm_uframes_t pos, int in_interrupt) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_pcm_hwptr_log *log = runtime->hwptr_log; - struct hwptr_log_entry *entry; - - if (log == NULL) { - log = kzalloc(sizeof(*log), GFP_ATOMIC); - if (log == NULL) - return; - runtime->hwptr_log = log; - } else { - if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit) - return; - } - entry = &log->entries[log->idx]; - entry->in_interrupt = in_interrupt; - entry->jiffies = jiffies; - entry->pos = pos; - entry->period_size = runtime->period_size; - entry->buffer_size = runtime->buffer_size; - entry->old_hw_ptr = runtime->status->hw_ptr; - entry->hw_ptr_base = runtime->hw_ptr_base; - log->idx = (log->idx + 1) % XRUN_LOG_CNT; -} - -static void xrun_log_show(struct snd_pcm_substream *substream) -{ - struct snd_pcm_hwptr_log *log = substream->runtime->hwptr_log; - struct hwptr_log_entry *entry; - char name[16]; - unsigned int idx; - int cnt; - - if (log == NULL) - return; - if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit) - return; - snd_pcm_debug_name(substream, name, sizeof(name)); - for (cnt = 0, idx = log->idx; cnt < XRUN_LOG_CNT; cnt++) { - entry = &log->entries[idx]; - if (entry->period_size == 0) - break; - pr_info("hwptr log: %s: %sj=%lu, pos=%ld/%ld/%ld, " - "hwptr=%ld/%ld\n", - name, entry->in_interrupt ? "[Q] " : "", - entry->jiffies, - (unsigned long)entry->pos, - (unsigned long)entry->period_size, - (unsigned long)entry->buffer_size, - (unsigned long)entry->old_hw_ptr, - (unsigned long)entry->hw_ptr_base); - idx++; - idx %= XRUN_LOG_CNT; - } - log->hit = 1; -} - #else /* ! CONFIG_SND_PCM_XRUN_DEBUG */ #define hw_ptr_error(substream, fmt, args...) do { } while (0) -#define xrun_log(substream, pos, in_interrupt) do { } while (0) -#define xrun_log_show(substream) do { } while (0) #endif @@ -343,7 +271,6 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, if (printk_ratelimit()) { char name[16]; snd_pcm_debug_name(substream, name, sizeof(name)); - xrun_log_show(substream); pcm_err(substream->pcm, "BUG: %s, pos = %ld, buffer size = %ld, period size = %ld\n", name, pos, runtime->buffer_size, @@ -352,8 +279,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, pos = 0; } pos -= pos % runtime->min_align; - if (xrun_debug(substream, XRUN_DEBUG_LOG)) - xrun_log(substream, pos, in_interrupt); + trace_hwptr(substream, pos, in_interrupt); hw_base = runtime->hw_ptr_base; new_hw_ptr = hw_base + pos; if (in_interrupt) { @@ -388,22 +314,6 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, delta = new_hw_ptr - old_hw_ptr; if (delta < 0) delta += runtime->boundary; - if (xrun_debug(substream, in_interrupt ? - XRUN_DEBUG_PERIODUPDATE : XRUN_DEBUG_HWPTRUPDATE)) { - char name[16]; - snd_pcm_debug_name(substream, name, sizeof(name)); - pcm_dbg(substream->pcm, - "%s_update: %s: pos=%u/%u/%u, hwptr=%ld/%ld/%ld/%ld\n", - in_interrupt ? "period" : "hwptr", - name, - (unsigned int)pos, - (unsigned int)runtime->period_size, - (unsigned int)runtime->buffer_size, - (unsigned long)delta, - (unsigned long)old_hw_ptr, - (unsigned long)new_hw_ptr, - (unsigned long)runtime->hw_ptr_base); - } if (runtime->no_period_wakeup) { snd_pcm_sframes_t xrun_threshold; @@ -431,13 +341,10 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, /* something must be really wrong */ if (delta >= runtime->buffer_size + runtime->period_size) { - hw_ptr_error(substream, - "Unexpected hw_pointer value %s" - "(stream=%i, pos=%ld, new_hw_ptr=%ld, " - "old_hw_ptr=%ld)\n", - in_interrupt ? "[Q] " : "[P]", - substream->stream, (long)pos, - (long)new_hw_ptr, (long)old_hw_ptr); + hw_ptr_error(substream, in_interrupt, "Unexpected hw_ptr", + "(stream=%i, pos=%ld, new_hw_ptr=%ld, old_hw_ptr=%ld)\n", + substream->stream, (long)pos, + (long)new_hw_ptr, (long)old_hw_ptr); return 0; } @@ -474,11 +381,8 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, delta--; } /* align hw_base to buffer_size */ - hw_ptr_error(substream, - "hw_ptr skipping! %s" - "(pos=%ld, delta=%ld, period=%ld, " - "jdelta=%lu/%lu/%lu, hw_ptr=%ld/%ld)\n", - in_interrupt ? "[Q] " : "", + hw_ptr_error(substream, in_interrupt, "hw_ptr skipping", + "(pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu/%lu, hw_ptr=%ld/%ld)\n", (long)pos, (long)hdelta, (long)runtime->period_size, jdelta, ((hdelta * HZ) / runtime->rate), hw_base, @@ -490,11 +394,9 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, } no_jiffies_check: if (delta > runtime->period_size + runtime->period_size / 2) { - hw_ptr_error(substream, - "Lost interrupts? %s" - "(stream=%i, delta=%ld, new_hw_ptr=%ld, " - "old_hw_ptr=%ld)\n", - in_interrupt ? "[Q] " : "", + hw_ptr_error(substream, in_interrupt, + "Lost interrupts?", + "(stream=%i, delta=%ld, new_hw_ptr=%ld, old_hw_ptr=%ld)\n", substream->stream, (long)delta, (long)new_hw_ptr, (long)old_hw_ptr); diff --git a/sound/core/pcm_trace.h b/sound/core/pcm_trace.h new file mode 100644 index 000000000000..b63b654da5ff --- /dev/null +++ b/sound/core/pcm_trace.h @@ -0,0 +1,110 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM snd_pcm +#define TRACE_INCLUDE_FILE pcm_trace + +#if !defined(_PCM_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define _PCM_TRACE_H + +#include + +TRACE_EVENT(hwptr, + TP_PROTO(struct snd_pcm_substream *substream, snd_pcm_uframes_t pos, bool irq), + TP_ARGS(substream, pos, irq), + TP_STRUCT__entry( + __field( bool, in_interrupt ) + __field( unsigned int, card ) + __field( unsigned int, device ) + __field( unsigned int, number ) + __field( unsigned int, stream ) + __field( snd_pcm_uframes_t, pos ) + __field( snd_pcm_uframes_t, period_size ) + __field( snd_pcm_uframes_t, buffer_size ) + __field( snd_pcm_uframes_t, old_hw_ptr ) + __field( snd_pcm_uframes_t, hw_ptr_base ) + ), + TP_fast_assign( + __entry->in_interrupt = (irq); + __entry->card = (substream)->pcm->card->number; + __entry->device = (substream)->pcm->device; + __entry->number = (substream)->number; + __entry->stream = (substream)->stream; + __entry->pos = (pos); + __entry->period_size = (substream)->runtime->period_size; + __entry->buffer_size = (substream)->runtime->buffer_size; + __entry->old_hw_ptr = (substream)->runtime->status->hw_ptr; + __entry->hw_ptr_base = (substream)->runtime->hw_ptr_base; + ), + TP_printk("pcmC%dD%d%c/sub%d: %s: pos=%lu, old=%lu, base=%lu, period=%lu, buf=%lu", + __entry->card, __entry->device, + __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c', + __entry->number, + __entry->in_interrupt ? "IRQ" : "POS", + (unsigned long)__entry->pos, + (unsigned long)__entry->old_hw_ptr, + (unsigned long)__entry->hw_ptr_base, + (unsigned long)__entry->period_size, + (unsigned long)__entry->buffer_size) +); + +TRACE_EVENT(xrun, + TP_PROTO(struct snd_pcm_substream *substream), + TP_ARGS(substream), + TP_STRUCT__entry( + __field( unsigned int, card ) + __field( unsigned int, device ) + __field( unsigned int, number ) + __field( unsigned int, stream ) + __field( snd_pcm_uframes_t, period_size ) + __field( snd_pcm_uframes_t, buffer_size ) + __field( snd_pcm_uframes_t, old_hw_ptr ) + __field( snd_pcm_uframes_t, hw_ptr_base ) + ), + TP_fast_assign( + __entry->card = (substream)->pcm->card->number; + __entry->device = (substream)->pcm->device; + __entry->number = (substream)->number; + __entry->stream = (substream)->stream; + __entry->period_size = (substream)->runtime->period_size; + __entry->buffer_size = (substream)->runtime->buffer_size; + __entry->old_hw_ptr = (substream)->runtime->status->hw_ptr; + __entry->hw_ptr_base = (substream)->runtime->hw_ptr_base; + ), + TP_printk("pcmC%dD%d%c/sub%d: XRUN: old=%lu, base=%lu, period=%lu, buf=%lu", + __entry->card, __entry->device, + __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c', + __entry->number, + (unsigned long)__entry->old_hw_ptr, + (unsigned long)__entry->hw_ptr_base, + (unsigned long)__entry->period_size, + (unsigned long)__entry->buffer_size) +); + +TRACE_EVENT(hw_ptr_error, + TP_PROTO(struct snd_pcm_substream *substream, const char *why), + TP_ARGS(substream, why), + TP_STRUCT__entry( + __field( unsigned int, card ) + __field( unsigned int, device ) + __field( unsigned int, number ) + __field( unsigned int, stream ) + __field( const char *, reason ) + ), + TP_fast_assign( + __entry->card = (substream)->pcm->card->number; + __entry->device = (substream)->pcm->device; + __entry->number = (substream)->number; + __entry->stream = (substream)->stream; + __entry->reason = (why); + ), + TP_printk("pcmC%dD%d%c/sub%d: ERROR: %s", + __entry->card, __entry->device, + __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c', + __entry->number, __entry->reason) +); + +#endif /* _PCM_TRACE_H */ + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#include -- cgit v1.2.3 From 2b30d411dbc6eddfb5b4f9afd5a2c57b6f4dd96c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 4 Nov 2014 14:02:40 +0100 Subject: ALSA: pcm: Add xrun_injection proc entry This patch adds a new proc entry for PCM substreams to inject an XRUN. When a PCM substream is running and any value is written to its xrun_injection proc file, the driver triggers XRUN. This is a useful feature for debugging XRUN and error handling code paths. Note that this entry is enabled only when CONFIG_SND_PCM_XRUN_DEBUG is set. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/Procfile.txt | 4 ++++ include/sound/pcm.h | 3 +++ sound/core/pcm.c | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+) (limited to 'sound') diff --git a/Documentation/sound/alsa/Procfile.txt b/Documentation/sound/alsa/Procfile.txt index cfc49567b9dc..7f8a0d325905 100644 --- a/Documentation/sound/alsa/Procfile.txt +++ b/Documentation/sound/alsa/Procfile.txt @@ -133,6 +133,10 @@ card*/pcm*/sub*/sw_params card*/pcm*/sub*/prealloc The buffer pre-allocation information. +card*/pcm*/sub*/xrun_injection + Triggers an XRUN to the running stream when any value is + written to this proc file. Used for fault injection. + This entry is write-only. AC97 Codec Information ---------------------- diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 29eb09ef2969..0b8daeed0a33 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -416,7 +416,10 @@ struct snd_pcm_substream { struct snd_info_entry *proc_status_entry; struct snd_info_entry *proc_prealloc_entry; struct snd_info_entry *proc_prealloc_max_entry; +#ifdef CONFIG_SND_PCM_XRUN_DEBUG + struct snd_info_entry *proc_xrun_injection_entry; #endif +#endif /* CONFIG_SND_VERBOSE_PROCFS */ /* misc flags */ unsigned int hw_opened: 1; }; diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 31acc3df62cd..8f624b7af0ca 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -483,6 +483,19 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry, } #ifdef CONFIG_SND_PCM_XRUN_DEBUG +static void snd_pcm_xrun_injection_write(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct snd_pcm_substream *substream = entry->private_data; + struct snd_pcm_runtime *runtime; + + snd_pcm_stream_lock_irq(substream); + runtime = substream->runtime; + if (runtime && runtime->status->state == SNDRV_PCM_STATE_RUNNING) + snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); + snd_pcm_stream_unlock_irq(substream); +} + static void snd_pcm_xrun_debug_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { @@ -614,6 +627,22 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) } substream->proc_status_entry = entry; +#ifdef CONFIG_SND_PCM_XRUN_DEBUG + entry = snd_info_create_card_entry(card, "xrun_injection", + substream->proc_root); + if (entry) { + entry->private_data = substream; + entry->c.text.read = NULL; + entry->c.text.write = snd_pcm_xrun_injection_write; + entry->mode = S_IFREG | S_IWUSR; + if (snd_info_register(entry) < 0) { + snd_info_free_entry(entry); + entry = NULL; + } + } + substream->proc_xrun_injection_entry = entry; +#endif /* CONFIG_SND_PCM_XRUN_DEBUG */ + return 0; } @@ -627,6 +656,10 @@ static int snd_pcm_substream_proc_done(struct snd_pcm_substream *substream) substream->proc_sw_params_entry = NULL; snd_info_free_entry(substream->proc_status_entry); substream->proc_status_entry = NULL; +#ifdef CONFIG_SND_PCM_XRUN_DEBUG + snd_info_free_entry(substream->proc_xrun_injection_entry); + substream->proc_xrun_injection_entry = NULL; +#endif snd_info_free_entry(substream->proc_root); substream->proc_root = NULL; return 0; -- cgit v1.2.3 From 4c8c3a4fcc021677c9a363b4e77f61dd09dbfd1a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 31 Oct 2014 11:00:23 +0100 Subject: ALSA: usb-audio: Flatten probe and disconnect functions The usb-audio probe and disconnect functions have been split just for adapting the (new!) API at 2.5 kernel time. We left them until now, partly because we wanted to build with the pretty old kernels in the external alsa-driver tree. But the support of such old kernels has been longly stopped, so it's good time to clean up this mess. One good point by this cleanup is that now the probe function returns a proper error code instead of only -EIO. Signed-off-by: Takashi Iwai --- sound/usb/card.c | 75 +++++++++++++++++++++++--------------------------------- 1 file changed, 30 insertions(+), 45 deletions(-) (limited to 'sound') diff --git a/sound/usb/card.c b/sound/usb/card.c index 7ecd0e8a5c51..be16bdc53c2a 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -112,7 +112,7 @@ static struct usb_driver usb_audio_driver; /* * disconnect streams - * called from snd_usb_audio_disconnect() + * called from usb_audio_disconnect() */ static void snd_usb_stream_disconnect(struct list_head *head) { @@ -475,14 +475,14 @@ static int snd_usb_audio_create(struct usb_interface *intf, * only at the first time. the successive calls of this function will * append the pcm interface to the corresponding card. */ -static struct snd_usb_audio * -snd_usb_audio_probe(struct usb_device *dev, - struct usb_interface *intf, - const struct usb_device_id *usb_id) +static int usb_audio_probe(struct usb_interface *intf, + const struct usb_device_id *usb_id) { - const struct snd_usb_audio_quirk *quirk = (const struct snd_usb_audio_quirk *)usb_id->driver_info; - int i, err; + struct usb_device *dev = interface_to_usbdev(intf); + const struct snd_usb_audio_quirk *quirk = + (const struct snd_usb_audio_quirk *)usb_id->driver_info; struct snd_usb_audio *chip; + int i, err; struct usb_host_interface *alts; int ifnum; u32 id; @@ -492,10 +492,11 @@ snd_usb_audio_probe(struct usb_device *dev, id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), le16_to_cpu(dev->descriptor.idProduct)); if (quirk && quirk->ifnum >= 0 && ifnum != quirk->ifnum) - goto __err_val; + return -ENXIO; - if (snd_usb_apply_boot_quirk(dev, intf, quirk) < 0) - goto __err_val; + err = snd_usb_apply_boot_quirk(dev, intf, quirk); + if (err < 0) + return err; /* * found a config. now register to ALSA @@ -508,6 +509,7 @@ snd_usb_audio_probe(struct usb_device *dev, if (usb_chip[i] && usb_chip[i]->dev == dev) { if (usb_chip[i]->shutdown) { dev_err(&dev->dev, "USB device is in the shutdown state, cannot create a card instance\n"); + err = -EIO; goto __error; } chip = usb_chip[i]; @@ -523,15 +525,16 @@ snd_usb_audio_probe(struct usb_device *dev, if (enable[i] && ! usb_chip[i] && (vid[i] == -1 || vid[i] == USB_ID_VENDOR(id)) && (pid[i] == -1 || pid[i] == USB_ID_PRODUCT(id))) { - if (snd_usb_audio_create(intf, dev, i, quirk, - &chip) < 0) { + err = snd_usb_audio_create(intf, dev, i, quirk, + &chip); + if (err < 0) goto __error; - } chip->pm_intf = intf; break; } if (!chip) { dev_err(&dev->dev, "no available usb audio device\n"); + err = -ENODEV; goto __error; } } @@ -548,28 +551,32 @@ snd_usb_audio_probe(struct usb_device *dev, err = 1; /* continue */ if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) { /* need some special handlings */ - if ((err = snd_usb_create_quirk(chip, intf, &usb_audio_driver, quirk)) < 0) + err = snd_usb_create_quirk(chip, intf, &usb_audio_driver, quirk); + if (err < 0) goto __error; } if (err > 0) { /* create normal USB audio interfaces */ - if (snd_usb_create_streams(chip, ifnum) < 0 || - snd_usb_create_mixer(chip, ifnum, ignore_ctl_error) < 0) { + err = snd_usb_create_streams(chip, ifnum); + if (err < 0) + goto __error; + err = snd_usb_create_mixer(chip, ifnum, ignore_ctl_error); + if (err < 0) goto __error; - } } /* we are allowed to call snd_card_register() many times */ - if (snd_card_register(chip->card) < 0) { + err = snd_card_register(chip->card); + if (err < 0) goto __error; - } usb_chip[chip->index] = chip; chip->num_interfaces++; chip->probing = 0; + usb_set_intfdata(intf, chip); mutex_unlock(®ister_mutex); - return chip; + return 0; __error: if (chip) { @@ -578,17 +585,16 @@ snd_usb_audio_probe(struct usb_device *dev, chip->probing = 0; } mutex_unlock(®ister_mutex); - __err_val: - return NULL; + return err; } /* * we need to take care of counter, since disconnection can be called also * many times as well as usb_audio_probe(). */ -static void snd_usb_audio_disconnect(struct usb_device *dev, - struct snd_usb_audio *chip) +static void usb_audio_disconnect(struct usb_interface *intf) { + struct snd_usb_audio *chip = usb_get_intfdata(intf); struct snd_card *card; struct list_head *p; @@ -630,27 +636,6 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, } } -/* - * new 2.5 USB kernel API - */ -static int usb_audio_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct snd_usb_audio *chip; - chip = snd_usb_audio_probe(interface_to_usbdev(intf), intf, id); - if (chip) { - usb_set_intfdata(intf, chip); - return 0; - } else - return -EIO; -} - -static void usb_audio_disconnect(struct usb_interface *intf) -{ - snd_usb_audio_disconnect(interface_to_usbdev(intf), - usb_get_intfdata(intf)); -} - #ifdef CONFIG_PM int snd_usb_autoresume(struct snd_usb_audio *chip) -- cgit v1.2.3 From a6cece9d81990e729c1f9da2a5bff2d29f7df649 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 31 Oct 2014 11:24:32 +0100 Subject: ALSA: usb-audio: Pass direct struct pointer instead of list_head Some functions in mixer.c and endpoint.c receive list_head instead of the object itself. This is not obvious and rather error-prone. Let's pass the proper object directly instead. The functions in midi.c still receive list_head and this can't be changed since the object definition isn't exposed to the outside of midi.c, so left as is. Signed-off-by: Takashi Iwai --- sound/usb/card.c | 20 ++++++++++---------- sound/usb/endpoint.c | 7 ++----- sound/usb/endpoint.h | 2 +- sound/usb/mixer.c | 5 +---- sound/usb/mixer.h | 2 +- 5 files changed, 15 insertions(+), 21 deletions(-) (limited to 'sound') diff --git a/sound/usb/card.c b/sound/usb/card.c index be16bdc53c2a..fa6c0972aa23 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -114,13 +114,11 @@ static struct usb_driver usb_audio_driver; * disconnect streams * called from usb_audio_disconnect() */ -static void snd_usb_stream_disconnect(struct list_head *head) +static void snd_usb_stream_disconnect(struct snd_usb_stream *as) { int idx; - struct snd_usb_stream *as; struct snd_usb_substream *subs; - as = list_entry(head, struct snd_usb_stream, list); for (idx = 0; idx < 2; idx++) { subs = &as->substream[idx]; if (!subs->num_formats) @@ -307,10 +305,10 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) static int snd_usb_audio_free(struct snd_usb_audio *chip) { - struct list_head *p, *n; + struct snd_usb_endpoint *ep, *n; - list_for_each_safe(p, n, &chip->ep_list) - snd_usb_endpoint_free(p); + list_for_each_entry_safe(ep, n, &chip->ep_list, list) + snd_usb_endpoint_free(ep); mutex_destroy(&chip->mutex); kfree(chip); @@ -609,12 +607,14 @@ static void usb_audio_disconnect(struct usb_interface *intf) mutex_lock(®ister_mutex); chip->num_interfaces--; if (chip->num_interfaces <= 0) { + struct snd_usb_stream *as; struct snd_usb_endpoint *ep; + struct usb_mixer_interface *mixer; snd_card_disconnect(card); /* release the pcm resources */ - list_for_each(p, &chip->pcm_list) { - snd_usb_stream_disconnect(p); + list_for_each_entry(as, &chip->pcm_list, list) { + snd_usb_stream_disconnect(as); } /* release the endpoint resources */ list_for_each_entry(ep, &chip->ep_list, list) { @@ -625,8 +625,8 @@ static void usb_audio_disconnect(struct usb_interface *intf) snd_usbmidi_disconnect(p); } /* release mixer resources */ - list_for_each(p, &chip->mixer_list) { - snd_usb_mixer_disconnect(p); + list_for_each_entry(mixer, &chip->mixer_list, list) { + snd_usb_mixer_disconnect(mixer); } usb_chip[chip->index] = NULL; mutex_unlock(®ister_mutex); diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 114e3e7ff511..167d0c1643e1 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -1002,15 +1002,12 @@ void snd_usb_endpoint_release(struct snd_usb_endpoint *ep) /** * snd_usb_endpoint_free: Free the resources of an snd_usb_endpoint * - * @ep: the list header of the endpoint to free + * @ep: the endpoint to free * * This free all resources of the given ep. */ -void snd_usb_endpoint_free(struct list_head *head) +void snd_usb_endpoint_free(struct snd_usb_endpoint *ep) { - struct snd_usb_endpoint *ep; - - ep = list_entry(head, struct snd_usb_endpoint, list); kfree(ep); } diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h index e61ee5c356a3..6428392d8f62 100644 --- a/sound/usb/endpoint.h +++ b/sound/usb/endpoint.h @@ -24,7 +24,7 @@ void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep); int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep); void snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep); void snd_usb_endpoint_release(struct snd_usb_endpoint *ep); -void snd_usb_endpoint_free(struct list_head *head); +void snd_usb_endpoint_free(struct snd_usb_endpoint *ep); int snd_usb_endpoint_implicit_feedback_sink(struct snd_usb_endpoint *ep); int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep); diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 63a8adb1705e..e4aaa21baed2 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -2483,11 +2483,8 @@ _error: return err; } -void snd_usb_mixer_disconnect(struct list_head *p) +void snd_usb_mixer_disconnect(struct usb_mixer_interface *mixer) { - struct usb_mixer_interface *mixer; - - mixer = list_entry(p, struct usb_mixer_interface, list); usb_kill_urb(mixer->urb); usb_kill_urb(mixer->rc_urb); } diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h index 73b1f649447b..2c7b9c9c2aa6 100644 --- a/sound/usb/mixer.h +++ b/sound/usb/mixer.h @@ -57,7 +57,7 @@ struct usb_mixer_elem_info { int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, int ignore_error); -void snd_usb_mixer_disconnect(struct list_head *p); +void snd_usb_mixer_disconnect(struct usb_mixer_interface *mixer); void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid); -- cgit v1.2.3 From ae366c2049b48b54e5250cb57438bbebd1dbe610 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 31 Oct 2014 11:32:19 +0100 Subject: ALSA: usb-audio: Use strim() instead of open code Signed-off-by: Takashi Iwai --- sound/usb/card.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/usb/card.c b/sound/usb/card.c index fa6c0972aa23..69725d5fa2d6 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -321,16 +321,6 @@ static int snd_usb_audio_dev_free(struct snd_device *device) return snd_usb_audio_free(chip); } -static void remove_trailing_spaces(char *str) -{ - char *p; - - if (!*str) - return; - for (p = str + strlen(str) - 1; p >= str && isspace(*p); p--) - *p = 0; -} - /* * create a chip instance and set its names. */ @@ -414,7 +404,7 @@ static int snd_usb_audio_create(struct usb_interface *intf, USB_ID_PRODUCT(chip->usb_id)); } } - remove_trailing_spaces(card->shortname); + strim(card->shortname); /* retrieve the vendor and device strings as longname */ if (quirk && quirk->vendor_name && *quirk->vendor_name) { @@ -428,7 +418,7 @@ static int snd_usb_audio_create(struct usb_interface *intf, /* we don't really care if there isn't any vendor string */ } if (len > 0) { - remove_trailing_spaces(card->longname); + strim(card->longname); if (*card->longname) strlcat(card->longname, " ", sizeof(card->longname)); } -- cgit v1.2.3 From 9161bd0d1cf375492f0a6aa86b3e4c28b070fb7c Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Wed, 5 Nov 2014 19:51:56 +0530 Subject: ALSA: echoaudio: cleanup of unnecessary messages commit "b5b4a41b392960010fccf1f9ccf8334d612bd450" was dereferencing chip after it has been freed. This patch fixes that and at the same time removes some debugging messages, which are unnecessary, as they are just printing information about entry and exit from a function, and which switch-case it is executing. we can easily get from ftrace the information about the entry and exit from a function. Reported-by: Dan Carpenter Signed-off-by: Sudip Mukherjee Signed-off-by: Takashi Iwai --- sound/pci/echoaudio/darla20_dsp.c | 2 -- sound/pci/echoaudio/darla24_dsp.c | 2 -- sound/pci/echoaudio/echo3g_dsp.c | 2 -- sound/pci/echoaudio/echoaudio.c | 31 ------------------------------- sound/pci/echoaudio/echoaudio_3g.c | 5 ----- sound/pci/echoaudio/echoaudio_dsp.c | 12 ------------ sound/pci/echoaudio/gina20_dsp.c | 6 ------ sound/pci/echoaudio/gina24_dsp.c | 9 --------- sound/pci/echoaudio/indigo_dsp.c | 2 -- sound/pci/echoaudio/indigodj_dsp.c | 2 -- sound/pci/echoaudio/indigodjx_dsp.c | 2 -- sound/pci/echoaudio/indigoio_dsp.c | 2 -- sound/pci/echoaudio/indigoiox_dsp.c | 2 -- sound/pci/echoaudio/layla20_dsp.c | 9 --------- sound/pci/echoaudio/layla24_dsp.c | 8 -------- sound/pci/echoaudio/mia_dsp.c | 2 -- sound/pci/echoaudio/midi.c | 6 ------ sound/pci/echoaudio/mona_dsp.c | 6 ------ 18 files changed, 110 deletions(-) (limited to 'sound') diff --git a/sound/pci/echoaudio/darla20_dsp.c b/sound/pci/echoaudio/darla20_dsp.c index c94e92e31ae6..febee5bda877 100644 --- a/sound/pci/echoaudio/darla20_dsp.c +++ b/sound/pci/echoaudio/darla20_dsp.c @@ -33,7 +33,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) { int err; - dev_dbg(chip->card->dev, "init_hw() - Darla20\n"); if (snd_BUG_ON((subdevice_id & 0xfff0) != DARLA20)) return -ENODEV; @@ -58,7 +57,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - dev_dbg(chip->card->dev, "init_hw: done\n"); return err; } diff --git a/sound/pci/echoaudio/darla24_dsp.c b/sound/pci/echoaudio/darla24_dsp.c index b1272f88d59d..7b4f6fd51b09 100644 --- a/sound/pci/echoaudio/darla24_dsp.c +++ b/sound/pci/echoaudio/darla24_dsp.c @@ -33,7 +33,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) { int err; - dev_dbg(chip->card->dev, "init_hw() - Darla24\n"); if (snd_BUG_ON((subdevice_id & 0xfff0) != DARLA24)) return -ENODEV; @@ -57,7 +56,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - dev_dbg(chip->card->dev, "init_hw: done\n"); return err; } diff --git a/sound/pci/echoaudio/echo3g_dsp.c b/sound/pci/echoaudio/echo3g_dsp.c index bc3716895fc8..ae11ce11b1c2 100644 --- a/sound/pci/echoaudio/echo3g_dsp.c +++ b/sound/pci/echoaudio/echo3g_dsp.c @@ -46,7 +46,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) int err; local_irq_enable(); - dev_dbg(chip->card->dev, "init_hw() - Echo3G\n"); if (snd_BUG_ON((subdevice_id & 0xfff0) != ECHO3G)) return -ENODEV; @@ -99,7 +98,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL | ECHOCAPS_HAS_DIGITAL_MODE_ADAT; - dev_dbg(chip->card->dev, "init_hw done\n"); return err; } diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 1ef29e5b53a7..60e40034b991 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -79,7 +79,6 @@ static void free_firmware(const struct firmware *fw_entry, dev_dbg(chip->card->dev, "firmware not released (kept in cache)\n"); #else release_firmware(fw_entry); - dev_dbg(chip->card->dev, "firmware released\n"); #endif } @@ -96,7 +95,6 @@ static void free_firmware_cache(struct echoaudio *chip) dev_dbg(chip->card->dev, "release_firmware(%d)\n", i); } - dev_dbg(chip->card->dev, "firmware_cache released\n"); #endif } @@ -354,7 +352,6 @@ static int pcm_analog_in_open(struct snd_pcm_substream *substream) struct echoaudio *chip = snd_pcm_substream_chip(substream); int err; - dev_dbg(chip->card->dev, "pcm_analog_in_open\n"); if ((err = pcm_open(substream, num_analog_busses_in(chip) - substream->number)) < 0) return err; @@ -389,7 +386,6 @@ static int pcm_analog_out_open(struct snd_pcm_substream *substream) #else max_channels = num_analog_busses_out(chip); #endif - dev_dbg(chip->card->dev, "pcm_analog_out_open\n"); if ((err = pcm_open(substream, max_channels - substream->number)) < 0) return err; if ((err = snd_pcm_hw_rule_add(substream->runtime, 0, @@ -422,7 +418,6 @@ static int pcm_digital_in_open(struct snd_pcm_substream *substream) struct echoaudio *chip = snd_pcm_substream_chip(substream); int err, max_channels; - dev_dbg(chip->card->dev, "pcm_digital_in_open\n"); max_channels = num_digital_busses_in(chip) - substream->number; mutex_lock(&chip->mode_mutex); if (chip->digital_mode == DIGITAL_MODE_ADAT) @@ -464,7 +459,6 @@ static int pcm_digital_out_open(struct snd_pcm_substream *substream) struct echoaudio *chip = snd_pcm_substream_chip(substream); int err, max_channels; - dev_dbg(chip->card->dev, "pcm_digital_out_open\n"); max_channels = num_digital_busses_out(chip) - substream->number; mutex_lock(&chip->mode_mutex); if (chip->digital_mode == DIGITAL_MODE_ADAT) @@ -511,7 +505,6 @@ static int pcm_close(struct snd_pcm_substream *substream) /* Nothing to do here. Audio is already off and pipe will be * freed by its callback */ - dev_dbg(chip->card->dev, "pcm_close\n"); atomic_dec(&chip->opencount); oc = atomic_read(&chip->opencount); @@ -620,7 +613,6 @@ static int init_engine(struct snd_pcm_substream *substream, spin_lock_irq(&chip->lock); set_sample_rate(chip, hw_params->rate_num / hw_params->rate_den); spin_unlock_irq(&chip->lock); - dev_dbg(chip->card->dev, "pcm_hw_params ok\n"); return 0; } @@ -691,7 +683,6 @@ static int pcm_hw_free(struct snd_pcm_substream *substream) } spin_unlock_irq(&chip->lock); - dev_dbg(chip->card->dev, "pcm_hw_freed\n"); snd_pcm_lib_free_pages(substream); return 0; } @@ -763,10 +754,8 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd) spin_lock(&chip->lock); switch (cmd) { case SNDRV_PCM_TRIGGER_RESUME: - dev_dbg(chip->card->dev, "pcm_trigger resume\n"); case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - dev_dbg(chip->card->dev, "pcm_trigger start\n"); for (i = 0; i < DSP_MAXPIPES; i++) { if (channelmask & (1 << i)) { pipe = chip->substream[i]->runtime->private_data; @@ -788,9 +777,7 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd) chip->pipe_cyclic_mask); break; case SNDRV_PCM_TRIGGER_SUSPEND: - dev_dbg(chip->card->dev, "pcm_trigger suspend\n"); case SNDRV_PCM_TRIGGER_STOP: - dev_dbg(chip->card->dev, "pcm_trigger stop\n"); for (i = 0; i < DSP_MAXPIPES; i++) { if (channelmask & (1 << i)) { pipe = chip->substream[i]->runtime->private_data; @@ -800,7 +787,6 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd) err = stop_transport(chip, channelmask); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - dev_dbg(chip->card->dev, "pcm_trigger pause\n"); for (i = 0; i < DSP_MAXPIPES; i++) { if (channelmask & (1 << i)) { pipe = chip->substream[i]->runtime->private_data; @@ -937,7 +923,6 @@ static int snd_echo_new_pcm(struct echoaudio *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &analog_capture_ops); if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0) return err; - dev_dbg(chip->card->dev, "Analog PCM ok\n"); #ifdef ECHOCARD_HAS_DIGITAL_IO /* PCM#1 Digital inputs, no outputs */ @@ -950,7 +935,6 @@ static int snd_echo_new_pcm(struct echoaudio *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &digital_capture_ops); if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0) return err; - dev_dbg(chip->card->dev, "Digital PCM ok\n"); #endif /* ECHOCARD_HAS_DIGITAL_IO */ #else /* ECHOCARD_HAS_VMIXER */ @@ -972,7 +956,6 @@ static int snd_echo_new_pcm(struct echoaudio *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &analog_capture_ops); if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0) return err; - dev_dbg(chip->card->dev, "Analog PCM ok\n"); #ifdef ECHOCARD_HAS_DIGITAL_IO /* PCM#1 Digital i/o */ @@ -987,7 +970,6 @@ static int snd_echo_new_pcm(struct echoaudio *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &digital_capture_ops); if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0) return err; - dev_dbg(chip->card->dev, "Digital PCM ok\n"); #endif /* ECHOCARD_HAS_DIGITAL_IO */ #endif /* ECHOCARD_HAS_VMIXER */ @@ -1881,10 +1863,8 @@ static irqreturn_t snd_echo_interrupt(int irq, void *dev_id) static int snd_echo_free(struct echoaudio *chip) { - dev_dbg(chip->card->dev, "Stop DSP...\n"); if (chip->comm_page) rest_in_peace(chip); - dev_dbg(chip->card->dev, "Stopped.\n"); if (chip->irq >= 0) free_irq(chip->irq, chip); @@ -1898,14 +1878,12 @@ static int snd_echo_free(struct echoaudio *chip) if (chip->iores) release_and_free_resource(chip->iores); - dev_dbg(chip->card->dev, "MMIO freed.\n"); pci_disable_device(chip->pci); /* release chip data */ free_firmware_cache(chip); kfree(chip); - dev_dbg(chip->card->dev, "Chip freed.\n"); return 0; } @@ -1915,7 +1893,6 @@ static int snd_echo_dev_free(struct snd_device *device) { struct echoaudio *chip = device->device_data; - dev_dbg(chip->card->dev, "snd_echo_dev_free()...\n"); return snd_echo_free(chip); } @@ -2008,7 +1985,6 @@ static int snd_echo_create(struct snd_card *card, snd_echo_free(chip); return err; } - dev_dbg(card->dev, "Card init OK\n"); if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_echo_free(chip); @@ -2038,7 +2014,6 @@ static int snd_echo_probe(struct pci_dev *pci, return -ENOENT; } - dev_dbg(&pci->dev, "Echoaudio driver starting...\n"); i = 0; err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, 0, &card); @@ -2191,7 +2166,6 @@ static int snd_echo_suspend(struct device *dev) struct pci_dev *pci = to_pci_dev(dev); struct echoaudio *chip = dev_get_drvdata(dev); - dev_dbg(dev, "suspend start\n"); snd_pcm_suspend_all(chip->analog_pcm); snd_pcm_suspend_all(chip->digital_pcm); @@ -2218,7 +2192,6 @@ static int snd_echo_suspend(struct device *dev) pci_save_state(pci); pci_disable_device(pci); - dev_dbg(dev, "suspend done\n"); return 0; } @@ -2232,7 +2205,6 @@ static int snd_echo_resume(struct device *dev) u32 pipe_alloc_mask; int err; - dev_dbg(dev, "resume start\n"); pci_restore_state(pci); commpage_bak = kmalloc(sizeof(struct echoaudio), GFP_KERNEL); if (commpage_bak == NULL) @@ -2247,7 +2219,6 @@ static int snd_echo_resume(struct device *dev) snd_echo_free(chip); return err; } - dev_dbg(dev, "resume init OK\n"); /* Temporarily set chip->pipe_alloc_mask=0 otherwise * restore_dsp_settings() fails. @@ -2260,7 +2231,6 @@ static int snd_echo_resume(struct device *dev) kfree(commpage_bak); return err; } - dev_dbg(dev, "resume restore OK\n"); memcpy(&commpage->audio_format, &commpage_bak->audio_format, sizeof(commpage->audio_format)); @@ -2286,7 +2256,6 @@ static int snd_echo_resume(struct device *dev) snd_echo_midi_output_trigger(chip->midi_out, 1); #endif - dev_dbg(dev, "resume done\n"); return 0; } diff --git a/sound/pci/echoaudio/echoaudio_3g.c b/sound/pci/echoaudio/echoaudio_3g.c index 50a21690447d..2fa66dc3e675 100644 --- a/sound/pci/echoaudio/echoaudio_3g.c +++ b/sound/pci/echoaudio/echoaudio_3g.c @@ -328,7 +328,6 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) { u32 control_reg, clocks_from_dsp; - dev_dbg(chip->card->dev, "set_input_clock:\n"); /* Mask off the clock select bits */ control_reg = le32_to_cpu(chip->comm_page->control_register) & @@ -337,13 +336,11 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) switch (clock) { case ECHO_CLOCK_INTERNAL: - dev_dbg(chip->card->dev, "Set Echo3G clock to INTERNAL\n"); chip->input_clock = ECHO_CLOCK_INTERNAL; return set_sample_rate(chip, chip->sample_rate); case ECHO_CLOCK_SPDIF: if (chip->digital_mode == DIGITAL_MODE_ADAT) return -EAGAIN; - dev_dbg(chip->card->dev, "Set Echo3G clock to SPDIF\n"); control_reg |= E3G_SPDIF_CLOCK; if (clocks_from_dsp & E3G_CLOCK_DETECT_BIT_SPDIF96) control_reg |= E3G_DOUBLE_SPEED_MODE; @@ -353,12 +350,10 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) case ECHO_CLOCK_ADAT: if (chip->digital_mode != DIGITAL_MODE_ADAT) return -EAGAIN; - dev_dbg(chip->card->dev, "Set Echo3G clock to ADAT\n"); control_reg |= E3G_ADAT_CLOCK; control_reg &= ~E3G_DOUBLE_SPEED_MODE; break; case ECHO_CLOCK_WORD: - dev_dbg(chip->card->dev, "Set Echo3G clock to WORD\n"); control_reg |= E3G_WORD_CLOCK; if (clocks_from_dsp & E3G_CLOCK_DETECT_BIT_WORD96) control_reg |= E3G_DOUBLE_SPEED_MODE; diff --git a/sound/pci/echoaudio/echoaudio_dsp.c b/sound/pci/echoaudio/echoaudio_dsp.c index ba9d4f16cbb3..1a9427aabe1d 100644 --- a/sound/pci/echoaudio/echoaudio_dsp.c +++ b/sound/pci/echoaudio/echoaudio_dsp.c @@ -206,7 +206,6 @@ static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic) goto la_error; } - dev_dbg(chip->card->dev, "ASIC loaded\n"); free_firmware(fw, chip); return 0; @@ -473,7 +472,6 @@ static int load_dsp(struct echoaudio *chip, u16 *code) chip->dsp_code = code; /* Show which DSP code loaded */ chip->bad_board = FALSE; /* DSP OK */ - dev_dbg(chip->card->dev, "load_dsp: OK!\n"); return 0; } udelay(100); @@ -674,7 +672,6 @@ static void get_audio_meters(struct echoaudio *chip, long *meters) static int restore_dsp_rettings(struct echoaudio *chip) { int i, o, err; - dev_dbg(chip->card->dev, "restore_dsp_settings\n"); if ((err = check_asic_status(chip)) < 0) return err; @@ -771,7 +768,6 @@ static int restore_dsp_rettings(struct echoaudio *chip) if (send_vector(chip, DSP_VC_UPDATE_FLAGS) < 0) return -EIO; - dev_dbg(chip->card->dev, "restore_dsp_rettings done\n"); return 0; } @@ -865,7 +861,6 @@ Same thing for pause_ and stop_ -trasport below. */ static int start_transport(struct echoaudio *chip, u32 channel_mask, u32 cyclic_mask) { - dev_dbg(chip->card->dev, "start_transport %x\n", channel_mask); if (wait_handshake(chip)) return -EIO; @@ -891,7 +886,6 @@ static int start_transport(struct echoaudio *chip, u32 channel_mask, static int pause_transport(struct echoaudio *chip, u32 channel_mask) { - dev_dbg(chip->card->dev, "pause_transport %x\n", channel_mask); if (wait_handshake(chip)) return -EIO; @@ -918,7 +912,6 @@ static int pause_transport(struct echoaudio *chip, u32 channel_mask) static int stop_transport(struct echoaudio *chip, u32 channel_mask) { - dev_dbg(chip->card->dev, "stop_transport %x\n", channel_mask); if (wait_handshake(chip)) return -EIO; @@ -954,8 +947,6 @@ static inline int is_pipe_allocated(struct echoaudio *chip, u16 pipe_index) stopped and unallocated. */ static int rest_in_peace(struct echoaudio *chip) { - dev_dbg(chip->card->dev, - "rest_in_peace() open=%x\n", chip->pipe_alloc_mask); /* Stops all active pipes (just to be sure) */ stop_transport(chip, chip->active_mask); @@ -1018,7 +1009,6 @@ static int init_dsp_comm_page(struct echoaudio *chip) */ static int init_line_levels(struct echoaudio *chip) { - dev_dbg(chip->card->dev, "init_line_levels\n"); memset(chip->output_gain, ECHOGAIN_MUTED, sizeof(chip->output_gain)); memset(chip->input_gain, ECHOGAIN_MUTED, sizeof(chip->input_gain)); memset(chip->monitor_gain, ECHOGAIN_MUTED, sizeof(chip->monitor_gain)); @@ -1099,7 +1089,6 @@ static int allocate_pipes(struct echoaudio *chip, struct audiopipe *pipe, it moves data. The DMA counter is in units of bytes, not samples. */ pipe->dma_counter = &chip->comm_page->position[pipe_index]; *pipe->dma_counter = 0; - dev_dbg(chip->card->dev, "allocate_pipes: ok\n"); return pipe_index; } @@ -1110,7 +1099,6 @@ static int free_pipes(struct echoaudio *chip, struct audiopipe *pipe) u32 channel_mask; int i; - dev_dbg(chip->card->dev, "free_pipes: Pipe %d\n", pipe->index); if (snd_BUG_ON(!is_pipe_allocated(chip, pipe->index))) return -EINVAL; if (snd_BUG_ON(pipe->state != PIPE_STATE_STOPPED)) diff --git a/sound/pci/echoaudio/gina20_dsp.c b/sound/pci/echoaudio/gina20_dsp.c index a959eae95e0d..5dafe9260cb4 100644 --- a/sound/pci/echoaudio/gina20_dsp.c +++ b/sound/pci/echoaudio/gina20_dsp.c @@ -37,7 +37,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) { int err; - dev_dbg(chip->card->dev, "init_hw() - Gina20\n"); if (snd_BUG_ON((subdevice_id & 0xfff0) != GINA20)) return -ENODEV; @@ -63,7 +62,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - dev_dbg(chip->card->dev, "init_hw done\n"); return err; } @@ -150,7 +148,6 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate) static int set_input_clock(struct echoaudio *chip, u16 clock) { - dev_dbg(chip->card->dev, "set_input_clock:\n"); switch (clock) { case ECHO_CLOCK_INTERNAL: @@ -159,7 +156,6 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) chip->spdif_status = GD_SPDIF_STATUS_UNDEF; set_sample_rate(chip, chip->sample_rate); chip->input_clock = clock; - dev_dbg(chip->card->dev, "Set Gina clock to INTERNAL\n"); break; case ECHO_CLOCK_SPDIF: chip->comm_page->gd_clock_state = GD_CLOCK_SPDIFIN; @@ -167,7 +163,6 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) clear_handshake(chip); send_vector(chip, DSP_VC_SET_GD_AUDIO_STATE); chip->clock_state = GD_CLOCK_SPDIFIN; - dev_dbg(chip->card->dev, "Set Gina20 clock to SPDIF\n"); chip->input_clock = clock; break; default: @@ -209,7 +204,6 @@ static int update_flags(struct echoaudio *chip) static int set_professional_spdif(struct echoaudio *chip, char prof) { - dev_dbg(chip->card->dev, "set_professional_spdif %d\n", prof); if (prof) chip->comm_page->flags |= cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF); diff --git a/sound/pci/echoaudio/gina24_dsp.c b/sound/pci/echoaudio/gina24_dsp.c index c8ea57612d22..6971766938bf 100644 --- a/sound/pci/echoaudio/gina24_dsp.c +++ b/sound/pci/echoaudio/gina24_dsp.c @@ -41,7 +41,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) { int err; - dev_dbg(chip->card->dev, "init_hw() - Gina24\n"); if (snd_BUG_ON((subdevice_id & 0xfff0) != GINA24)) return -ENODEV; @@ -79,7 +78,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - dev_dbg(chip->card->dev, "init_hw done\n"); return err; } @@ -156,7 +154,6 @@ static int load_asic(struct echoaudio *chip) control_reg = GML_CONVERTER_ENABLE | GML_48KHZ; err = write_control_reg(chip, control_reg, TRUE); } - dev_dbg(chip->card->dev, "load_asic() done\n"); return err; } @@ -238,7 +235,6 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) { u32 control_reg, clocks_from_dsp; - dev_dbg(chip->card->dev, "set_input_clock:\n"); /* Mask off the clock select bits */ control_reg = le32_to_cpu(chip->comm_page->control_register) & @@ -247,13 +243,11 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) switch (clock) { case ECHO_CLOCK_INTERNAL: - dev_dbg(chip->card->dev, "Set Gina24 clock to INTERNAL\n"); chip->input_clock = ECHO_CLOCK_INTERNAL; return set_sample_rate(chip, chip->sample_rate); case ECHO_CLOCK_SPDIF: if (chip->digital_mode == DIGITAL_MODE_ADAT) return -EAGAIN; - dev_dbg(chip->card->dev, "Set Gina24 clock to SPDIF\n"); control_reg |= GML_SPDIF_CLOCK; if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_SPDIF96) control_reg |= GML_DOUBLE_SPEED_MODE; @@ -263,17 +257,14 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) case ECHO_CLOCK_ADAT: if (chip->digital_mode != DIGITAL_MODE_ADAT) return -EAGAIN; - dev_dbg(chip->card->dev, "Set Gina24 clock to ADAT\n"); control_reg |= GML_ADAT_CLOCK; control_reg &= ~GML_DOUBLE_SPEED_MODE; break; case ECHO_CLOCK_ESYNC: - dev_dbg(chip->card->dev, "Set Gina24 clock to ESYNC\n"); control_reg |= GML_ESYNC_CLOCK; control_reg &= ~GML_DOUBLE_SPEED_MODE; break; case ECHO_CLOCK_ESYNC96: - dev_dbg(chip->card->dev, "Set Gina24 clock to ESYNC96\n"); control_reg |= GML_ESYNC_CLOCK | GML_DOUBLE_SPEED_MODE; break; default: diff --git a/sound/pci/echoaudio/indigo_dsp.c b/sound/pci/echoaudio/indigo_dsp.c index cdeb073fad85..54edd67edff7 100644 --- a/sound/pci/echoaudio/indigo_dsp.c +++ b/sound/pci/echoaudio/indigo_dsp.c @@ -38,7 +38,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) { int err; - dev_dbg(chip->card->dev, "init_hw() - Indigo\n"); if (snd_BUG_ON((subdevice_id & 0xfff0) != INDIGO)) return -ENODEV; @@ -61,7 +60,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - dev_dbg(chip->card->dev, "init_hw done\n"); return err; } diff --git a/sound/pci/echoaudio/indigodj_dsp.c b/sound/pci/echoaudio/indigodj_dsp.c index 133915ca6438..2cf5cc092d7a 100644 --- a/sound/pci/echoaudio/indigodj_dsp.c +++ b/sound/pci/echoaudio/indigodj_dsp.c @@ -38,7 +38,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) { int err; - dev_dbg(chip->card->dev, "init_hw() - Indigo DJ\n"); if (snd_BUG_ON((subdevice_id & 0xfff0) != INDIGO_DJ)) return -ENODEV; @@ -61,7 +60,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - dev_dbg(chip->card->dev, "init_hw done\n"); return err; } diff --git a/sound/pci/echoaudio/indigodjx_dsp.c b/sound/pci/echoaudio/indigodjx_dsp.c index 26cdfcfc5553..5252863f1681 100644 --- a/sound/pci/echoaudio/indigodjx_dsp.c +++ b/sound/pci/echoaudio/indigodjx_dsp.c @@ -35,7 +35,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) { int err; - dev_dbg(chip->card->dev, "init_hw() - Indigo DJx\n"); if (snd_BUG_ON((subdevice_id & 0xfff0) != INDIGO_DJX)) return -ENODEV; @@ -60,7 +59,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - dev_dbg(chip->card->dev, "init_hw done\n"); return err; } diff --git a/sound/pci/echoaudio/indigoio_dsp.c b/sound/pci/echoaudio/indigoio_dsp.c index 5e6df7c25055..4e81787627e0 100644 --- a/sound/pci/echoaudio/indigoio_dsp.c +++ b/sound/pci/echoaudio/indigoio_dsp.c @@ -38,7 +38,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) { int err; - dev_dbg(chip->card->dev, "init_hw() - Indigo IO\n"); if (snd_BUG_ON((subdevice_id & 0xfff0) != INDIGO_IO)) return -ENODEV; @@ -61,7 +60,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - dev_dbg(chip->card->dev, "init_hw done\n"); return err; } diff --git a/sound/pci/echoaudio/indigoiox_dsp.c b/sound/pci/echoaudio/indigoiox_dsp.c index 90cdd271d9fc..6de3f9bc6d26 100644 --- a/sound/pci/echoaudio/indigoiox_dsp.c +++ b/sound/pci/echoaudio/indigoiox_dsp.c @@ -35,7 +35,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) { int err; - dev_dbg(chip->card->dev, "init_hw() - Indigo IOx\n"); if (snd_BUG_ON((subdevice_id & 0xfff0) != INDIGO_IOX)) return -ENODEV; @@ -60,7 +59,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - dev_dbg(chip->card->dev, "init_hw done\n"); return err; } diff --git a/sound/pci/echoaudio/layla20_dsp.c b/sound/pci/echoaudio/layla20_dsp.c index 7f0f6ea08ca7..f2024a3565af 100644 --- a/sound/pci/echoaudio/layla20_dsp.c +++ b/sound/pci/echoaudio/layla20_dsp.c @@ -40,7 +40,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) { int err; - dev_dbg(chip->card->dev, "init_hw() - Layla20\n"); if (snd_BUG_ON((subdevice_id & 0xfff0) != LAYLA20)) return -ENODEV; @@ -65,7 +64,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - dev_dbg(chip->card->dev, "init_hw done\n"); return err; } @@ -190,24 +188,19 @@ static int set_input_clock(struct echoaudio *chip, u16 clock_source) u16 clock; u32 rate; - dev_dbg(chip->card->dev, "set_input_clock:\n"); rate = 0; switch (clock_source) { case ECHO_CLOCK_INTERNAL: - dev_dbg(chip->card->dev, "Set Layla20 clock to INTERNAL\n"); rate = chip->sample_rate; clock = LAYLA20_CLOCK_INTERNAL; break; case ECHO_CLOCK_SPDIF: - dev_dbg(chip->card->dev, "Set Layla20 clock to SPDIF\n"); clock = LAYLA20_CLOCK_SPDIF; break; case ECHO_CLOCK_WORD: - dev_dbg(chip->card->dev, "Set Layla20 clock to WORD\n"); clock = LAYLA20_CLOCK_WORD; break; case ECHO_CLOCK_SUPER: - dev_dbg(chip->card->dev, "Set Layla20 clock to SUPER\n"); clock = LAYLA20_CLOCK_SUPER; break; default: @@ -232,7 +225,6 @@ static int set_input_clock(struct echoaudio *chip, u16 clock_source) static int set_output_clock(struct echoaudio *chip, u16 clock) { - dev_dbg(chip->card->dev, "set_output_clock: %d\n", clock); switch (clock) { case ECHO_CLOCK_SUPER: clock = LAYLA20_OUTPUT_CLOCK_SUPER; @@ -286,7 +278,6 @@ static int update_flags(struct echoaudio *chip) static int set_professional_spdif(struct echoaudio *chip, char prof) { - dev_dbg(chip->card->dev, "set_professional_spdif %d\n", prof); if (prof) chip->comm_page->flags |= cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF); diff --git a/sound/pci/echoaudio/layla24_dsp.c b/sound/pci/echoaudio/layla24_dsp.c index eb8f218f79fe..4f11e81f6c0e 100644 --- a/sound/pci/echoaudio/layla24_dsp.c +++ b/sound/pci/echoaudio/layla24_dsp.c @@ -40,7 +40,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) { int err; - dev_dbg(chip->card->dev, "init_hw() - Layla24\n"); if (snd_BUG_ON((subdevice_id & 0xfff0) != LAYLA24)) return -ENODEV; @@ -70,7 +69,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) if ((err = init_line_levels(chip)) < 0) return err; - dev_dbg(chip->card->dev, "init_hw done\n"); return err; } @@ -118,7 +116,6 @@ static int load_asic(struct echoaudio *chip) if (chip->asic_loaded) return 1; - dev_dbg(chip->card->dev, "load_asic\n"); /* Give the DSP a few milliseconds to settle down */ mdelay(10); @@ -152,7 +149,6 @@ static int load_asic(struct echoaudio *chip) err = write_control_reg(chip, GML_CONVERTER_ENABLE | GML_48KHZ, TRUE); - dev_dbg(chip->card->dev, "load_asic() done\n"); return err; } @@ -262,7 +258,6 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) /* Pick the new clock */ switch (clock) { case ECHO_CLOCK_INTERNAL: - dev_dbg(chip->card->dev, "Set Layla24 clock to INTERNAL\n"); chip->input_clock = ECHO_CLOCK_INTERNAL; return set_sample_rate(chip, chip->sample_rate); case ECHO_CLOCK_SPDIF: @@ -271,7 +266,6 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) control_reg |= GML_SPDIF_CLOCK; /* Layla24 doesn't support 96KHz S/PDIF */ control_reg &= ~GML_DOUBLE_SPEED_MODE; - dev_dbg(chip->card->dev, "Set Layla24 clock to SPDIF\n"); break; case ECHO_CLOCK_WORD: control_reg |= GML_WORD_CLOCK; @@ -279,14 +273,12 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) control_reg |= GML_DOUBLE_SPEED_MODE; else control_reg &= ~GML_DOUBLE_SPEED_MODE; - dev_dbg(chip->card->dev, "Set Layla24 clock to WORD\n"); break; case ECHO_CLOCK_ADAT: if (chip->digital_mode != DIGITAL_MODE_ADAT) return -EAGAIN; control_reg |= GML_ADAT_CLOCK; control_reg &= ~GML_DOUBLE_SPEED_MODE; - dev_dbg(chip->card->dev, "Set Layla24 clock to ADAT\n"); break; default: dev_err(chip->card->dev, diff --git a/sound/pci/echoaudio/mia_dsp.c b/sound/pci/echoaudio/mia_dsp.c index ed2f21dcd1c9..fdad079ad9a1 100644 --- a/sound/pci/echoaudio/mia_dsp.c +++ b/sound/pci/echoaudio/mia_dsp.c @@ -41,7 +41,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) { int err; - dev_dbg(chip->card->dev, "init_hw() - Mia\n"); if (snd_BUG_ON((subdevice_id & 0xfff0) != MIA)) return -ENODEV; @@ -67,7 +66,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - dev_dbg(chip->card->dev, "init_hw done\n"); return err; } diff --git a/sound/pci/echoaudio/midi.c b/sound/pci/echoaudio/midi.c index 8d43c5a4976b..d913749d154a 100644 --- a/sound/pci/echoaudio/midi.c +++ b/sound/pci/echoaudio/midi.c @@ -157,7 +157,6 @@ static int snd_echo_midi_input_open(struct snd_rawmidi_substream *substream) struct echoaudio *chip = substream->rmidi->private_data; chip->midi_in = substream; - dev_dbg(chip->card->dev, "rawmidi_iopen\n"); return 0; } @@ -183,7 +182,6 @@ static int snd_echo_midi_input_close(struct snd_rawmidi_substream *substream) struct echoaudio *chip = substream->rmidi->private_data; chip->midi_in = NULL; - dev_dbg(chip->card->dev, "rawmidi_iclose\n"); return 0; } @@ -196,7 +194,6 @@ static int snd_echo_midi_output_open(struct snd_rawmidi_substream *substream) chip->tinuse = 0; chip->midi_full = 0; chip->midi_out = substream; - dev_dbg(chip->card->dev, "rawmidi_open\n"); return 0; } @@ -209,7 +206,6 @@ static void snd_echo_midi_output_write(unsigned long data) int bytes, sent, time; unsigned char buf[MIDI_OUT_BUFFER_SIZE - 1]; - dev_dbg(chip->card->dev, "snd_echo_midi_output_write\n"); /* No interrupts are involved: we have to check at regular intervals if the card's output buffer has room for new data. */ sent = bytes = 0; @@ -288,7 +284,6 @@ static int snd_echo_midi_output_close(struct snd_rawmidi_substream *substream) struct echoaudio *chip = substream->rmidi->private_data; chip->midi_out = NULL; - dev_dbg(chip->card->dev, "rawmidi_oclose\n"); return 0; } @@ -328,6 +323,5 @@ static int snd_echo_midi_create(struct snd_card *card, chip->rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; - dev_dbg(chip->card->dev, "MIDI ok\n"); return 0; } diff --git a/sound/pci/echoaudio/mona_dsp.c b/sound/pci/echoaudio/mona_dsp.c index cc46a8c8e3dd..843c7a5e5105 100644 --- a/sound/pci/echoaudio/mona_dsp.c +++ b/sound/pci/echoaudio/mona_dsp.c @@ -41,7 +41,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) { int err; - dev_dbg(chip->card->dev, "init_hw() - Mona\n"); if (snd_BUG_ON((subdevice_id & 0xfff0) != MONA)) return -ENODEV; @@ -72,7 +71,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - dev_dbg(chip->card->dev, "init_hw done\n"); return err; } @@ -302,7 +300,6 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) u32 control_reg, clocks_from_dsp; int err; - dev_dbg(chip->card->dev, "set_input_clock:\n"); /* Prevent two simultaneous calls to switch_asic() */ if (atomic_read(&chip->opencount)) @@ -315,7 +312,6 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) switch (clock) { case ECHO_CLOCK_INTERNAL: - dev_dbg(chip->card->dev, "Set Mona clock to INTERNAL\n"); chip->input_clock = ECHO_CLOCK_INTERNAL; return set_sample_rate(chip, chip->sample_rate); case ECHO_CLOCK_SPDIF: @@ -327,7 +323,6 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) spin_lock_irq(&chip->lock); if (err < 0) return err; - dev_dbg(chip->card->dev, "Set Mona clock to SPDIF\n"); control_reg |= GML_SPDIF_CLOCK; if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_SPDIF96) control_reg |= GML_DOUBLE_SPEED_MODE; @@ -335,7 +330,6 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) control_reg &= ~GML_DOUBLE_SPEED_MODE; break; case ECHO_CLOCK_WORD: - dev_dbg(chip->card->dev, "Set Mona clock to WORD\n"); spin_unlock_irq(&chip->lock); err = switch_asic(chip, clocks_from_dsp & GML_CLOCK_DETECT_BIT_WORD96); -- cgit v1.2.3 From 9bc889b4ba88a3f2d81e4b799d47d71d7381573a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 6 Nov 2014 12:15:25 +0100 Subject: ALSA: pcm: Update the state properly before notification Some state changes (e.g. snd_pcm_stop()) sets the runtime state after calling snd_timer_notify(). This is basically racy, since the notification may wakes up the user even before the state change. Although the possibility is low, we should set the state before the notifications. Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index ca224fa2a33a..dfb5031969f8 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1052,10 +1052,10 @@ static void snd_pcm_post_stop(struct snd_pcm_substream *substream, int state) struct snd_pcm_runtime *runtime = substream->runtime; if (runtime->status->state != state) { snd_pcm_trigger_tstamp(substream); + runtime->status->state = state; if (substream->timer) snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTOP, &runtime->trigger_tstamp); - runtime->status->state = state; } wake_up(&runtime->sleep); wake_up(&runtime->tsleep); @@ -1204,11 +1204,11 @@ static void snd_pcm_post_suspend(struct snd_pcm_substream *substream, int state) { struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_trigger_tstamp(substream); + runtime->status->suspended_state = runtime->status->state; + runtime->status->state = SNDRV_PCM_STATE_SUSPENDED; if (substream->timer) snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSUSPEND, &runtime->trigger_tstamp); - runtime->status->suspended_state = runtime->status->state; - runtime->status->state = SNDRV_PCM_STATE_SUSPENDED; wake_up(&runtime->sleep); wake_up(&runtime->tsleep); } @@ -1311,10 +1311,10 @@ static void snd_pcm_post_resume(struct snd_pcm_substream *substream, int state) { struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_trigger_tstamp(substream); + runtime->status->state = runtime->status->suspended_state; if (substream->timer) snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MRESUME, &runtime->trigger_tstamp); - runtime->status->state = runtime->status->suspended_state; } static struct action_ops snd_pcm_action_resume = { -- cgit v1.2.3 From 67e225009bb15403341d313f51326113c61af7df Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 6 Nov 2014 13:04:49 +0100 Subject: ALSA: usb-audio: Trigger PCM XRUN at XRUN The usb-audio driver detects XRUN at its complete callback, but the actual code to trigger PCM XRUN is commented out because it caused deadlock in the past. This patch revives the PCM trigger properly. It resulted in more than just enabling snd_pcm_stop(), but it had to deduce the PCM substream with proper NULL checks and holds the stream lock around the call. Signed-off-by: Takashi Iwai --- sound/usb/endpoint.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 167d0c1643e1..a4679913b0aa 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -348,6 +348,8 @@ static void snd_complete_urb(struct urb *urb) { struct snd_urb_ctx *ctx = urb->context; struct snd_usb_endpoint *ep = ctx->ep; + struct snd_pcm_substream *substream; + unsigned long flags; int err; if (unlikely(urb->status == -ENOENT || /* unlinked */ @@ -364,8 +366,6 @@ static void snd_complete_urb(struct urb *urb) goto exit_clear; if (snd_usb_endpoint_implicit_feedback_sink(ep)) { - unsigned long flags; - spin_lock_irqsave(&ep->lock, flags); list_add_tail(&ctx->ready_list, &ep->ready_playback_urbs); spin_unlock_irqrestore(&ep->lock, flags); @@ -389,7 +389,12 @@ static void snd_complete_urb(struct urb *urb) return; usb_audio_err(ep->chip, "cannot submit urb (err = %d)\n", err); - //snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); + if (ep->data_subs && ep->data_subs->pcm_substream) { + substream = ep->data_subs->pcm_substream; + snd_pcm_stream_lock_irqsave(substream, flags); + snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); + snd_pcm_stream_unlock_irqrestore(substream, flags); + } exit_clear: clear_bit(ctx->index, &ep->active_mask); -- cgit v1.2.3 From 31584ed18c073176a7ad96ddbfd09765e21e813d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 7 Nov 2014 14:12:34 +0100 Subject: ALSA: snd_ctl_activate_id(): Fix index look-up We want to know the offset for the id that was passed to the function, not the offset of the first id of the control (which is always 0). Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai --- sound/core/control.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/core/control.c b/sound/core/control.c index 99aa3aa157ba..bb96a467e88d 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -572,7 +572,7 @@ int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id, ret = -ENOENT; goto unlock; } - index_offset = snd_ctl_get_ioff(kctl, &kctl->id); + index_offset = snd_ctl_get_ioff(kctl, id); vd = &kctl->vd[index_offset]; ret = 0; if (active) { -- cgit v1.2.3 From 1fb8510cdb5b7befe8a59f533c7fc12ef0dac73e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 7 Nov 2014 17:08:28 +0100 Subject: ALSA: pcm: Add snd_pcm_stop_xrun() helper Add a new helper function snd_pcm_stop_xrun() to the standard sequnce lock/snd_pcm_stop(XRUN)/unlock by a single call, and replace the existing open codes with this helper. The function checks the PCM running state to prevent setting the wrong state, too, for more safety. Signed-off-by: Takashi Iwai --- drivers/media/pci/saa7134/saa7134-alsa.c | 4 +--- include/sound/pcm.h | 1 + sound/arm/pxa2xx-pcm-lib.c | 4 +--- sound/core/pcm_native.c | 23 +++++++++++++++++++++++ sound/firewire/amdtp.c | 8 ++------ sound/firewire/isight.c | 10 ++-------- sound/pci/asihpi/asihpi.c | 5 +---- sound/pci/atiixp.c | 4 +--- sound/pci/atiixp_modem.c | 4 +--- sound/soc/atmel/atmel-pcm-dma.c | 4 +--- sound/soc/fsl/fsl_dma.c | 9 +-------- sound/usb/6fire/pcm.c | 17 ++++------------- sound/usb/endpoint.c | 4 +--- sound/usb/misc/ua101.c | 18 ++++-------------- sound/usb/usx2y/usbusx2yaudio.c | 9 ++------- 15 files changed, 46 insertions(+), 78 deletions(-) (limited to 'sound') diff --git a/drivers/media/pci/saa7134/saa7134-alsa.c b/drivers/media/pci/saa7134/saa7134-alsa.c index 40569894c1c9..ac3cd74e824e 100644 --- a/drivers/media/pci/saa7134/saa7134-alsa.c +++ b/drivers/media/pci/saa7134/saa7134-alsa.c @@ -173,9 +173,7 @@ static void saa7134_irq_alsa_done(struct saa7134_dev *dev, dprintk("irq: overrun [full=%d/%d] - Blocks in %d\n",dev->dmasound.read_count, dev->dmasound.bufsize, dev->dmasound.blocks); spin_unlock(&dev->slock); - snd_pcm_stream_lock(dev->dmasound.substream); - snd_pcm_stop(dev->dmasound.substream,SNDRV_PCM_STATE_XRUN); - snd_pcm_stream_unlock(dev->dmasound.substream); + snd_pcm_stop_xrun(dev->dmasound.substream); return; } diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 0b8daeed0a33..40289ec2451c 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -506,6 +506,7 @@ int snd_pcm_status(struct snd_pcm_substream *substream, int snd_pcm_start(struct snd_pcm_substream *substream); int snd_pcm_stop(struct snd_pcm_substream *substream, snd_pcm_state_t status); int snd_pcm_drain_done(struct snd_pcm_substream *substream); +int snd_pcm_stop_xrun(struct snd_pcm_substream *substream); #ifdef CONFIG_PM int snd_pcm_suspend(struct snd_pcm_substream *substream); int snd_pcm_suspend_all(struct snd_pcm *pcm); diff --git a/sound/arm/pxa2xx-pcm-lib.c b/sound/arm/pxa2xx-pcm-lib.c index a61d7a9a995e..01f8fdc42b1b 100644 --- a/sound/arm/pxa2xx-pcm-lib.c +++ b/sound/arm/pxa2xx-pcm-lib.c @@ -200,9 +200,7 @@ void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id) } else { printk(KERN_ERR "DMA error on channel %d (DCSR=%#x)\n", dma_ch, dcsr); - snd_pcm_stream_lock(substream); - snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); - snd_pcm_stream_unlock(substream); + snd_pcm_stop_xrun(substream); } } EXPORT_SYMBOL(pxa2xx_pcm_dma_irq); diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index dfb5031969f8..a3d122109704 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1098,6 +1098,29 @@ int snd_pcm_drain_done(struct snd_pcm_substream *substream) SNDRV_PCM_STATE_SETUP); } +/** + * snd_pcm_stop_xrun - stop the running streams as XRUN + * @substream: the PCM substream instance + * @state: PCM state after stopping the stream + * + * This stops the given running substream (and all linked substreams) as XRUN. + * Unlike snd_pcm_stop(), this function takes the substream lock by itself. + * + * Return: Zero if successful, or a negative error code. + */ +int snd_pcm_stop_xrun(struct snd_pcm_substream *substream) +{ + unsigned long flags; + int ret = 0; + + snd_pcm_stream_lock_irqsave(substream, flags); + if (snd_pcm_running(substream)) + ret = snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); + snd_pcm_stream_unlock_irqrestore(substream, flags); + return ret; +} +EXPORT_SYMBOL_GPL(snd_pcm_stop_xrun); + /* * pause callbacks */ diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c index 95fc2eaf11dc..3badc70124ab 100644 --- a/sound/firewire/amdtp.c +++ b/sound/firewire/amdtp.c @@ -1006,11 +1006,7 @@ void amdtp_stream_pcm_abort(struct amdtp_stream *s) struct snd_pcm_substream *pcm; pcm = ACCESS_ONCE(s->pcm); - if (pcm) { - snd_pcm_stream_lock_irq(pcm); - if (snd_pcm_running(pcm)) - snd_pcm_stop(pcm, SNDRV_PCM_STATE_XRUN); - snd_pcm_stream_unlock_irq(pcm); - } + if (pcm) + snd_pcm_stop_xrun(pcm); } EXPORT_SYMBOL(amdtp_stream_pcm_abort); diff --git a/sound/firewire/isight.c b/sound/firewire/isight.c index 7ac94439e758..48d6dca471c6 100644 --- a/sound/firewire/isight.c +++ b/sound/firewire/isight.c @@ -131,14 +131,8 @@ static void isight_samples(struct isight *isight, static void isight_pcm_abort(struct isight *isight) { - unsigned long flags; - - if (ACCESS_ONCE(isight->pcm_active)) { - snd_pcm_stream_lock_irqsave(isight->pcm, flags); - if (snd_pcm_running(isight->pcm)) - snd_pcm_stop(isight->pcm, SNDRV_PCM_STATE_XRUN); - snd_pcm_stream_unlock_irqrestore(isight->pcm, flags); - } + if (ACCESS_ONCE(isight->pcm_active)) + snd_pcm_stop_xrun(isight->pcm); } static void isight_dropped_samples(struct isight *isight, unsigned int total) diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index ac66b3228a34..ff9f9f1c0391 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c @@ -769,10 +769,7 @@ static void snd_card_asihpi_timer_function(unsigned long data) s->number); ds->drained_count++; if (ds->drained_count > 20) { - unsigned long flags; - snd_pcm_stream_lock_irqsave(s, flags); - snd_pcm_stop(s, SNDRV_PCM_STATE_XRUN); - snd_pcm_stream_unlock_irqrestore(s, flags); + snd_pcm_stop_xrun(s); continue; } } else { diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 7895c5d300c7..9c1c4452a8ee 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -688,9 +688,7 @@ static void snd_atiixp_xrun_dma(struct atiixp *chip, struct atiixp_dma *dma) if (! dma->substream || ! dma->running) return; dev_dbg(chip->card->dev, "XRUN detected (DMA %d)\n", dma->ops->type); - snd_pcm_stream_lock(dma->substream); - snd_pcm_stop(dma->substream, SNDRV_PCM_STATE_XRUN); - snd_pcm_stream_unlock(dma->substream); + snd_pcm_stop_xrun(dma->substream); } /* diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index 3c3241309a30..b2f63e0727de 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -638,9 +638,7 @@ static void snd_atiixp_xrun_dma(struct atiixp_modem *chip, if (! dma->substream || ! dma->running) return; dev_dbg(chip->card->dev, "XRUN detected (DMA %d)\n", dma->ops->type); - snd_pcm_stream_lock(dma->substream); - snd_pcm_stop(dma->substream, SNDRV_PCM_STATE_XRUN); - snd_pcm_stream_unlock(dma->substream); + snd_pcm_stop_xrun(dma->substream); } /* diff --git a/sound/soc/atmel/atmel-pcm-dma.c b/sound/soc/atmel/atmel-pcm-dma.c index b79a2a864513..33fb3bb133df 100644 --- a/sound/soc/atmel/atmel-pcm-dma.c +++ b/sound/soc/atmel/atmel-pcm-dma.c @@ -80,9 +80,7 @@ static void atmel_pcm_dma_irq(u32 ssc_sr, /* stop RX and capture: will be enabled again at restart */ ssc_writex(prtd->ssc->regs, SSC_CR, prtd->mask->ssc_disable); - snd_pcm_stream_lock(substream); - snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); - snd_pcm_stream_unlock(substream); + snd_pcm_stop_xrun(substream); /* now drain RHR and read status to remove xrun condition */ ssc_readx(prtd->ssc->regs, SSC_RHR); diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index a609aafc994d..b2b108805b24 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c @@ -151,14 +151,7 @@ static const struct snd_pcm_hardware fsl_dma_hardware = { */ static void fsl_dma_abort_stream(struct snd_pcm_substream *substream) { - unsigned long flags; - - snd_pcm_stream_lock_irqsave(substream, flags); - - if (snd_pcm_running(substream)) - snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); - - snd_pcm_stream_unlock_irqrestore(substream, flags); + snd_pcm_stop_xrun(substream); } /** diff --git a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c index ba40489b2de4..36f4115eb1cd 100644 --- a/sound/usb/6fire/pcm.c +++ b/sound/usb/6fire/pcm.c @@ -679,25 +679,16 @@ int usb6fire_pcm_init(struct sfire_chip *chip) void usb6fire_pcm_abort(struct sfire_chip *chip) { struct pcm_runtime *rt = chip->pcm; - unsigned long flags; int i; if (rt) { rt->panic = true; - if (rt->playback.instance) { - snd_pcm_stream_lock_irqsave(rt->playback.instance, flags); - snd_pcm_stop(rt->playback.instance, - SNDRV_PCM_STATE_XRUN); - snd_pcm_stream_unlock_irqrestore(rt->playback.instance, flags); - } + if (rt->playback.instance) + snd_pcm_stop_xrun(rt->playback.instance); - if (rt->capture.instance) { - snd_pcm_stream_lock_irqsave(rt->capture.instance, flags); - snd_pcm_stop(rt->capture.instance, - SNDRV_PCM_STATE_XRUN); - snd_pcm_stream_unlock_irqrestore(rt->capture.instance, flags); - } + if (rt->capture.instance) + snd_pcm_stop_xrun(rt->capture.instance); for (i = 0; i < PCM_N_URBS; i++) { usb_poison_urb(&rt->in_urbs[i].instance); diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index a4679913b0aa..03b074419964 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -391,9 +391,7 @@ static void snd_complete_urb(struct urb *urb) usb_audio_err(ep->chip, "cannot submit urb (err = %d)\n", err); if (ep->data_subs && ep->data_subs->pcm_substream) { substream = ep->data_subs->pcm_substream; - snd_pcm_stream_lock_irqsave(substream, flags); - snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); - snd_pcm_stream_unlock_irqrestore(substream, flags); + snd_pcm_stop_xrun(substream); } exit_clear: diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c index a1bab149df4d..9581089c28c5 100644 --- a/sound/usb/misc/ua101.c +++ b/sound/usb/misc/ua101.c @@ -613,24 +613,14 @@ static int start_usb_playback(struct ua101 *ua) static void abort_alsa_capture(struct ua101 *ua) { - unsigned long flags; - - if (test_bit(ALSA_CAPTURE_RUNNING, &ua->states)) { - snd_pcm_stream_lock_irqsave(ua->capture.substream, flags); - snd_pcm_stop(ua->capture.substream, SNDRV_PCM_STATE_XRUN); - snd_pcm_stream_unlock_irqrestore(ua->capture.substream, flags); - } + if (test_bit(ALSA_CAPTURE_RUNNING, &ua->states)) + snd_pcm_stop_xrun(ua->capture.substream); } static void abort_alsa_playback(struct ua101 *ua) { - unsigned long flags; - - if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states)) { - snd_pcm_stream_lock_irqsave(ua->playback.substream, flags); - snd_pcm_stop(ua->playback.substream, SNDRV_PCM_STATE_XRUN); - snd_pcm_stream_unlock_irqrestore(ua->playback.substream, flags); - } + if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states)) + snd_pcm_stop_xrun(ua->playback.substream); } static int set_stream_hw(struct ua101 *ua, struct snd_pcm_substream *substream, diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c index a63330dd1407..61d5dc2a3421 100644 --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c @@ -272,13 +272,8 @@ static void usX2Y_clients_stop(struct usX2Ydev *usX2Y) for (s = 0; s < 4; s++) { struct snd_usX2Y_substream *subs = usX2Y->subs[s]; if (subs) { - if (atomic_read(&subs->state) >= state_PRERUNNING) { - unsigned long flags; - - snd_pcm_stream_lock_irqsave(subs->pcm_substream, flags); - snd_pcm_stop(subs->pcm_substream, SNDRV_PCM_STATE_XRUN); - snd_pcm_stream_unlock_irqrestore(subs->pcm_substream, flags); - } + if (atomic_read(&subs->state) >= state_PRERUNNING) + snd_pcm_stop_xrun(subs->pcm_substream); for (u = 0; u < NRURBS; u++) { struct urb *urb = subs->urb[u]; if (NULL != urb) -- cgit v1.2.3 From d4b8fc66f770e9b79830cfe6c342846293b99fda Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 9 Nov 2014 18:21:23 +0100 Subject: ALSA: usb-audio: Allow multiple entries for the same iface in composite quirk Currently the composite quirk doesn't work when multiple entries are assigned to the same interface because it marks the interface as claimed then checks whether the interface has been already claimed for the secondary entry. But, if you look at the code, you'll notice that multiple entries are allowed if the entry is the current interface; i.e. the current behavior is anyway inconsistent, and this is an unintended shortcoming. This patch fixes the problem by marking the relevant interfaces as claimed after applying the all composite entries. This fix will be needed for the upcoming enhancements for Digidesign Mbox 1 quirks. Reviewed-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/usb/quirks.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index d2aa45a8d895..e9ff3a6c60e4 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -58,9 +58,17 @@ static int create_composite_quirk(struct snd_usb_audio *chip, err = snd_usb_create_quirk(chip, iface, driver, quirk); if (err < 0) return err; - if (quirk->ifnum != probed_ifnum) + } + + for (quirk = quirk->data; quirk->ifnum >= 0; ++quirk) { + iface = usb_ifnum_to_if(chip->dev, quirk->ifnum); + if (!iface) + continue; + if (quirk->ifnum != probed_ifnum && + !usb_interface_claimed(iface)) usb_driver_claim_interface(driver, iface, (void *)-1L); } + return 0; } -- cgit v1.2.3 From 48b217aa43abc8c3545bb9b4d7a5b525b71d6ac2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 10 Nov 2014 07:38:22 +0100 Subject: ALSA: pcm: Fix document for snd_pcm_stop_xrun() Fix a copy & paste error: Warning(sound/core/pcm_native.c:1112): Excess function parameter 'state' description in 'snd_pcm_stop_xrun' The state argument was dropped from snd_pcm_stop_xrun(). Reported-by: kbuild test robot Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index a3d122109704..095d9572ad2b 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1101,7 +1101,6 @@ int snd_pcm_drain_done(struct snd_pcm_substream *substream) /** * snd_pcm_stop_xrun - stop the running streams as XRUN * @substream: the PCM substream instance - * @state: PCM state after stopping the stream * * This stops the given running substream (and all linked substreams) as XRUN. * Unlike snd_pcm_stop(), this function takes the substream lock by itself. -- cgit v1.2.3 From 85a8181329a919d58b7ef99211251f47d5e1049e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 10 Nov 2014 07:41:59 +0100 Subject: ALSA: usb-audio: Fix Oops by composite quirk enhancement The quirk argument itself was used as iterator, so it cannot be taken back to the original value, obviously. Fixes: d4b8fc66f770 ('ALSA: usb-audio: Allow multiple entries for the same iface in composite quirk') Signed-off-by: Takashi Iwai --- sound/usb/quirks.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index e9ff3a6c60e4..809d7fab4633 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -43,12 +43,13 @@ static int create_composite_quirk(struct snd_usb_audio *chip, struct usb_interface *iface, struct usb_driver *driver, - const struct snd_usb_audio_quirk *quirk) + const struct snd_usb_audio_quirk *quirk_comp) { int probed_ifnum = get_iface_desc(iface->altsetting)->bInterfaceNumber; + const struct snd_usb_audio_quirk *quirk; int err; - for (quirk = quirk->data; quirk->ifnum >= 0; ++quirk) { + for (quirk = quirk_comp->data; quirk->ifnum >= 0; ++quirk) { iface = usb_ifnum_to_if(chip->dev, quirk->ifnum); if (!iface) continue; @@ -60,7 +61,7 @@ static int create_composite_quirk(struct snd_usb_audio *chip, return err; } - for (quirk = quirk->data; quirk->ifnum >= 0; ++quirk) { + for (quirk = quirk_comp->data; quirk->ifnum >= 0; ++quirk) { iface = usb_ifnum_to_if(chip->dev, quirk->ifnum); if (!iface) continue; -- cgit v1.2.3 From 2a9e8df00951092e825144a9968285398f8aa162 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 10 Nov 2014 16:46:35 +0100 Subject: ALSA: vx: Fix missing kerneldoc parameter descriptions The file isn't processed, but it's not bad to fix beforehand. Signed-off-by: Takashi Iwai --- sound/drivers/vx/vx_core.c | 10 ++++++++++ sound/pci/vx222/vx222_ops.c | 5 +++++ sound/pcmcia/vx/vxpocket.c | 1 + 3 files changed, 16 insertions(+) (limited to 'sound') diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c index e8cc16993903..fc05a37fd017 100644 --- a/sound/drivers/vx/vx_core.c +++ b/sound/drivers/vx/vx_core.c @@ -416,6 +416,7 @@ int vx_send_rih(struct vx_core *chip, int cmd) /** * snd_vx_boot_xilinx - boot up the xilinx interface + * @chip: VX core instance * @boot: the boot record to load */ int snd_vx_load_boot_image(struct vx_core *chip, const struct firmware *boot) @@ -538,6 +539,8 @@ EXPORT_SYMBOL(snd_vx_threaded_irq_handler); /** * snd_vx_irq_handler - interrupt handler + * @irq: irq number + * @dev: VX core instance */ irqreturn_t snd_vx_irq_handler(int irq, void *dev) { @@ -649,6 +652,8 @@ static void vx_proc_init(struct vx_core *chip) /** * snd_vx_dsp_boot - load the DSP boot + * @chip: VX core instance + * @boot: firmware data */ int snd_vx_dsp_boot(struct vx_core *chip, const struct firmware *boot) { @@ -669,6 +674,8 @@ EXPORT_SYMBOL(snd_vx_dsp_boot); /** * snd_vx_dsp_load - load the DSP image + * @chip: VX core instance + * @dsp: firmware data */ int snd_vx_dsp_load(struct vx_core *chip, const struct firmware *dsp) { @@ -768,7 +775,10 @@ EXPORT_SYMBOL(snd_vx_resume); /** * snd_vx_create - constructor for struct vx_core + * @card: card instance * @hw: hardware specific record + * @ops: VX ops pointer + * @extra_size: extra byte size to allocate appending to chip * * this function allocates the instance and prepare for the hardware * initialization. diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c index 2d1570273e99..52c1a8d5b88a 100644 --- a/sound/pci/vx222/vx222_ops.c +++ b/sound/pci/vx222/vx222_ops.c @@ -92,6 +92,7 @@ static inline unsigned long vx2_reg_addr(struct vx_core *_chip, int reg) /** * snd_vx_inb - read a byte from the register + * @chip: VX core instance * @offset: register enum */ static unsigned char vx2_inb(struct vx_core *chip, int offset) @@ -101,6 +102,7 @@ static unsigned char vx2_inb(struct vx_core *chip, int offset) /** * snd_vx_outb - write a byte on the register + * @chip: VX core instance * @offset: the register offset * @val: the value to write */ @@ -114,6 +116,7 @@ static void vx2_outb(struct vx_core *chip, int offset, unsigned char val) /** * snd_vx_inl - read a 32bit word from the register + * @chip: VX core instance * @offset: register enum */ static unsigned int vx2_inl(struct vx_core *chip, int offset) @@ -123,6 +126,7 @@ static unsigned int vx2_inl(struct vx_core *chip, int offset) /** * snd_vx_outl - write a 32bit word on the register + * @chip: VX core instance * @offset: the register enum * @val: the value to write */ @@ -223,6 +227,7 @@ static int vx2_test_xilinx(struct vx_core *_chip) /** * vx_setup_pseudo_dma - set up the pseudo dma read/write mode. + * @chip: VX core instance * @do_write: 0 = read, 1 = set up for DMA write */ static void vx2_setup_pseudo_dma(struct vx_core *chip, int do_write) diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c index 92ec11456e3a..b16f42deed67 100644 --- a/sound/pcmcia/vx/vxpocket.c +++ b/sound/pcmcia/vx/vxpocket.c @@ -174,6 +174,7 @@ static int snd_vxpocket_new(struct snd_card *card, int ibl, /** * snd_vxpocket_assign_resources - initialize the hardware and card instance. + * @chip: VX core instance * @port: i/o port for the card * @irq: irq number for the card * -- cgit v1.2.3 From e60b2c7fcdef03256cde864d678df240877a5e80 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 10 Nov 2014 16:47:26 +0100 Subject: ALSA: hda - Fix kerneldoc errors in patch_ca0132.c Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 4f7ffa8c4a0d..e0383eea9880 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -2417,7 +2417,7 @@ static int dspxfr_one_seg(struct hda_codec *codec, * @reloc: Relocation address for loading single-segment overlays, or 0 for * no relocation * @sample_rate: sampling rate of the stream used for DSP download - * @number_channels: channels of the stream used for DSP download + * @channels: channels of the stream used for DSP download * @ovly: TRUE if overlay format is required * * Returns zero or a negative error code. @@ -2556,10 +2556,7 @@ static void dspload_post_setup(struct hda_codec *codec) } /** - * Download DSP from a DSP Image Fast Load structure. This structure is a - * linear, non-constant sized element array of structures, each of which - * contain the count of the data to be loaded, the data itself, and the - * corresponding starting chip address of the starting data location. + * dspload_image - Download DSP from a DSP Image Fast Load structure. * * @codec: the HDA codec * @fls: pointer to a fast load image @@ -2570,6 +2567,10 @@ static void dspload_post_setup(struct hda_codec *codec) * @router_chans: number of audio router channels to be allocated (0 means use * internal defaults; max is 32) * + * Download DSP from a DSP Image Fast Load structure. This structure is a + * linear, non-constant sized element array of structures, each of which + * contain the count of the data to be loaded, the data itself, and the + * corresponding starting chip address of the starting data location. * Returns zero or a negative error code. */ static int dspload_image(struct hda_codec *codec, -- cgit v1.2.3 From 3f60c87d129acbb232afbc7269c726d009a01869 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 10 Nov 2014 17:09:22 +0100 Subject: ALSA: mixart: Fix kerneldoc comments Signed-off-by: Takashi Iwai --- sound/pci/mixart/mixart_hwdep.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/pci/mixart/mixart_hwdep.c b/sound/pci/mixart/mixart_hwdep.c index 581e1e74863c..9996a4dead0f 100644 --- a/sound/pci/mixart/mixart_hwdep.c +++ b/sound/pci/mixart/mixart_hwdep.c @@ -37,10 +37,11 @@ /** * wait for a value on a peudo register, exit with a timeout * - * @param mgr pointer to miXart manager structure - * @param offset unsigned pseudo_register base + offset of value - * @param value value - * @param timeout timeout in centisenconds + * @mgr: pointer to miXart manager structure + * @offset: unsigned pseudo_register base + offset of value + * @is_egal: wait for the equal value + * @value: value + * @timeout: timeout in centisenconds */ static int mixart_wait_nice_for_register_value(struct mixart_mgr *mgr, u32 offset, int is_egal, -- cgit v1.2.3 From ddcecf6b6ae7b91c8735e52f50cd403ee9cbe298 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 10 Nov 2014 17:24:26 +0100 Subject: ALSA: Fix invalid kerneldoc markers They are no real kerneldoc comments, so drop such markers. Signed-off-by: Takashi Iwai --- include/uapi/sound/hdspm.h | 12 +++++------ sound/pci/emu10k1/emu10k1x.c | 2 +- sound/pci/lx6464es/lx_defs.h | 2 +- sound/pci/rme9652/hdspm.c | 48 ++++++++++++++++++++++---------------------- 4 files changed, 32 insertions(+), 32 deletions(-) (limited to 'sound') diff --git a/include/uapi/sound/hdspm.h b/include/uapi/sound/hdspm.h index d956c3593f65..b357f1a5e29c 100644 --- a/include/uapi/sound/hdspm.h +++ b/include/uapi/sound/hdspm.h @@ -74,14 +74,14 @@ struct hdspm_config { #define SNDRV_HDSPM_IOCTL_GET_CONFIG \ _IOR('H', 0x41, struct hdspm_config) -/** +/* * If there's a TCO (TimeCode Option) board installed, * there are further options and status data available. * The hdspm_ltc structure contains the current SMPTE * timecode and some status information and can be * obtained via SNDRV_HDSPM_IOCTL_GET_LTC or in the * hdspm_status struct. - **/ + */ enum hdspm_ltc_format { format_invalid, @@ -113,11 +113,11 @@ struct hdspm_ltc { #define SNDRV_HDSPM_IOCTL_GET_LTC _IOR('H', 0x46, struct hdspm_ltc) -/** +/* * The status data reflects the device's current state * as determined by the card's configuration and * connection status. - **/ + */ enum hdspm_sync { hdspm_sync_no_lock = 0, @@ -171,9 +171,9 @@ struct hdspm_status { #define SNDRV_HDSPM_IOCTL_GET_STATUS \ _IOR('H', 0x47, struct hdspm_status) -/** +/* * Get information about the card and its add-ons. - **/ + */ #define HDSPM_ADDON_TCO 1 diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index e223de1408c0..15933f92f63a 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -180,7 +180,7 @@ MODULE_PARM_DESC(enable, "Enable the EMU10K1X soundcard."); /* From 0x50 - 0x5f, last samples captured */ -/** +/* * The hardware has 3 channels for playback and 1 for capture. * - channel 0 is the front channel * - channel 1 is the rear channel diff --git a/sound/pci/lx6464es/lx_defs.h b/sound/pci/lx6464es/lx_defs.h index 49d36bdd512c..469bcc685edf 100644 --- a/sound/pci/lx6464es/lx_defs.h +++ b/sound/pci/lx6464es/lx_defs.h @@ -175,7 +175,7 @@ enum buffer_flags { BF_ZERO = 0x00, /* no flags (init).*/ }; -/** +/* * Stream Flags definitions */ enum stream_flags { diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index e09348c156d8..3342705a5715 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -2201,10 +2201,10 @@ static inline int hdspm_get_pll_freq(struct hdspm *hdspm) return rate; } -/** +/* * Calculate the real sample rate from the * current DDS value. - **/ + */ static int hdspm_get_system_sample_rate(struct hdspm *hdspm) { unsigned int rate; @@ -2270,9 +2270,9 @@ static int snd_hdspm_put_system_sample_rate(struct snd_kcontrol *kcontrol, } -/** +/* * Returns the WordClock sample rate class for the given card. - **/ + */ static int hdspm_get_wc_sample_rate(struct hdspm *hdspm) { int status; @@ -2295,9 +2295,9 @@ static int hdspm_get_wc_sample_rate(struct hdspm *hdspm) } -/** +/* * Returns the TCO sample rate class for the given card. - **/ + */ static int hdspm_get_tco_sample_rate(struct hdspm *hdspm) { int status; @@ -2321,9 +2321,9 @@ static int hdspm_get_tco_sample_rate(struct hdspm *hdspm) } -/** +/* * Returns the SYNC_IN sample rate class for the given card. - **/ + */ static int hdspm_get_sync_in_sample_rate(struct hdspm *hdspm) { int status; @@ -2343,9 +2343,9 @@ static int hdspm_get_sync_in_sample_rate(struct hdspm *hdspm) return 0; } -/** +/* * Returns the AES sample rate class for the given card. - **/ + */ static int hdspm_get_aes_sample_rate(struct hdspm *hdspm, int index) { int timecode; @@ -2361,10 +2361,10 @@ static int hdspm_get_aes_sample_rate(struct hdspm *hdspm, int index) return 0; } -/** +/* * Returns the sample rate class for input source for * 'new style' cards like the AIO and RayDAT. - **/ + */ static int hdspm_get_s1_sample_rate(struct hdspm *hdspm, unsigned int idx) { int status = hdspm_read(hdspm, HDSPM_RD_STATUS_2); @@ -2512,10 +2512,10 @@ static int snd_hdspm_get_autosync_sample_rate(struct snd_kcontrol *kcontrol, } -/** +/* * Returns the system clock mode for the given card. * @returns 0 - master, 1 - slave - **/ + */ static int hdspm_system_clock_mode(struct hdspm *hdspm) { switch (hdspm->io_type) { @@ -2534,10 +2534,10 @@ static int hdspm_system_clock_mode(struct hdspm *hdspm) } -/** +/* * Sets the system clock mode. * @param mode 0 - master, 1 - slave - **/ + */ static void hdspm_set_system_clock_mode(struct hdspm *hdspm, int mode) { hdspm_set_toggle_setting(hdspm, @@ -2692,11 +2692,11 @@ static int snd_hdspm_put_clock_source(struct snd_kcontrol *kcontrol, } -/** +/* * Returns the current preferred sync reference setting. * The semantics of the return value are depending on the * card, please see the comments for clarification. - **/ + */ static int hdspm_pref_sync_ref(struct hdspm * hdspm) { switch (hdspm->io_type) { @@ -2795,11 +2795,11 @@ static int hdspm_pref_sync_ref(struct hdspm * hdspm) } -/** +/* * Set the preferred sync reference to . The semantics * of are depending on the card type, see the comments * for clarification. - **/ + */ static int hdspm_set_pref_sync_ref(struct hdspm * hdspm, int pref) { int p = 0; @@ -4101,9 +4101,9 @@ static int snd_hdspm_get_sync_check(struct snd_kcontrol *kcontrol, -/** +/* * TCO controls - **/ + */ static void hdspm_tco_write(struct hdspm *hdspm) { unsigned int tc[4] = { 0, 0, 0, 0}; @@ -5403,7 +5403,7 @@ static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id) HDSPM_midi2IRQPending | HDSPM_midi3IRQPending); /* now = get_cycles(); */ - /** + /* * LAT_2..LAT_0 period counter (win) counter (mac) * 6 4096 ~256053425 ~514672358 * 5 2048 ~128024983 ~257373821 @@ -5412,7 +5412,7 @@ static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id) * 2 256 ~16003039 ~32260176 * 1 128 ~7998738 ~16194507 * 0 64 ~3998231 ~8191558 - **/ + */ /* dev_info(hdspm->card->dev, "snd_hdspm_interrupt %llu @ %llx\n", now-hdspm->last_interrupt, status & 0xFFC0); -- cgit v1.2.3 From d497a82fb18ed4b73c08f8b5a0935f937e2ea1fb Mon Sep 17 00:00:00 2001 From: Damien Zammit Date: Wed, 12 Nov 2014 01:09:54 +1100 Subject: ALSA: usb-audio: Add mixer control for Digidesign Mbox 1 clock source This patch provides the infrastructure for the Digidesign Mbox 1 to have a mixer control for selecting the clock source. Valid options are Internal and S/PDIF external sync. A non-documented command is sent to the device to enable this feature found by reverse engineering and bus snooping. Signed-off-by: Damien Zammit Signed-off-by: Takashi Iwai --- sound/usb/mixer_maps.c | 9 ++++ sound/usb/mixer_quirks.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) (limited to 'sound') diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c index d1d72ff50347..1994d41348f8 100644 --- a/sound/usb/mixer_maps.c +++ b/sound/usb/mixer_maps.c @@ -179,6 +179,11 @@ static struct usbmix_name_map audigy2nx_map[] = { { 0 } /* terminator */ }; +static struct usbmix_name_map mbox1_map[] = { + { 1, "Clock" }, + { 0 } /* terminator */ +}; + static struct usbmix_selector_map c400_selectors[] = { { .id = 0x80, @@ -415,6 +420,10 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = { .id = USB_ID(0x0ccd, 0x0028), .map = aureon_51_2_map, }, + { + .id = USB_ID(0x0dba, 0x1000), + .map = mbox1_map, + }, { .id = USB_ID(0x13e5, 0x0001), .map = scratch_live_map, diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 3980bf554c83..45203168ac6d 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -565,6 +565,131 @@ static int snd_xonar_u1_controls_create(struct usb_mixer_interface *mixer) return 0; } +/* Digidesign Mbox 1 clock source switch (internal/spdif) */ + +static int snd_mbox1_switch_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.enumerated.item[0] = kctl->private_value; + return 0; +} + +static int snd_mbox1_switch_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_usb_audio *chip; + struct usb_mixer_interface *mixer; + int err; + bool cur_val, new_val; + unsigned char buff[3]; + + cur_val = kctl->private_value; + new_val = ucontrol->value.enumerated.item[0]; + + mixer = snd_kcontrol_chip(kctl); + if (snd_BUG_ON(!mixer)) + return -EINVAL; + + chip = mixer->chip; + if (snd_BUG_ON(!chip)) + return -EINVAL; + + if (cur_val == new_val) + return 0; + + down_read(&chip->shutdown_rwsem); + if (chip->shutdown) { + err = -ENODEV; + goto err; + } + + /* Prepare for magic command to toggle clock source */ + err = snd_usb_ctl_msg(chip->dev, + usb_rcvctrlpipe(chip->dev, 0), 0x81, + USB_DIR_IN | + USB_TYPE_CLASS | + USB_RECIP_INTERFACE, 0x00, 0x500, buff, 1); + if (err < 0) + goto err; + err = snd_usb_ctl_msg(chip->dev, + usb_rcvctrlpipe(chip->dev, 0), 0x81, + USB_DIR_IN | + USB_TYPE_CLASS | + USB_RECIP_ENDPOINT, 0x100, 0x81, buff, 3); + if (err < 0) + goto err; + + /* 2 possibilities: Internal -> send sample rate + * S/PDIF sync -> send zeroes + * NB: Sample rate locked to 48kHz on purpose to + * prevent user from resetting the sample rate + * while S/PDIF sync is enabled and confusing + * this configuration. + */ + if (new_val == 0) { + buff[0] = 0x80; + buff[1] = 0xbb; + buff[2] = 0x00; + } else { + buff[0] = buff[1] = buff[2] = 0x00; + } + + /* Send the magic command to toggle the clock source */ + err = snd_usb_ctl_msg(chip->dev, + usb_sndctrlpipe(chip->dev, 0), 0x1, + USB_TYPE_CLASS | + USB_RECIP_ENDPOINT, 0x100, 0x81, buff, 3); + if (err < 0) + goto err; + err = snd_usb_ctl_msg(chip->dev, + usb_rcvctrlpipe(chip->dev, 0), 0x81, + USB_DIR_IN | + USB_TYPE_CLASS | + USB_RECIP_ENDPOINT, 0x100, 0x81, buff, 3); + if (err < 0) + goto err; + err = snd_usb_ctl_msg(chip->dev, + usb_rcvctrlpipe(chip->dev, 0), 0x81, + USB_DIR_IN | + USB_TYPE_CLASS | + USB_RECIP_ENDPOINT, 0x100, 0x2, buff, 3); + if (err < 0) + goto err; + kctl->private_value = new_val; + +err: + up_read(&chip->shutdown_rwsem); + return err < 0 ? err : 1; +} + +static int snd_mbox1_switch_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static const char *const texts[2] = { + "Internal", + "S/PDIF" + }; + + return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); +} + +static struct snd_kcontrol_new snd_mbox1_switch = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Clock Source", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = snd_mbox1_switch_info, + .get = snd_mbox1_switch_get, + .put = snd_mbox1_switch_put, + .private_value = 0 +}; + +static int snd_mbox1_create_sync_switch(struct usb_mixer_interface *mixer) +{ + return snd_ctl_add(mixer->chip->card, + snd_ctl_new1(&snd_mbox1_switch, mixer)); +} + /* Native Instruments device quirks */ #define _MAKE_NI_CONTROL(bRequest,wIndex) ((bRequest) << 16 | (wIndex)) @@ -1632,6 +1757,10 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) err = snd_microii_controls_create(mixer); break; + case USB_ID(0x0dba, 0x1000): /* Digidesign Mbox 1 */ + err = snd_mbox1_create_sync_switch(mixer); + break; + case USB_ID(0x17cc, 0x1011): /* Traktor Audio 6 */ err = snd_nativeinstruments_create_mixer(mixer, snd_nativeinstruments_ta6_mixers, -- cgit v1.2.3 From c63fcb9b67777b906c4515a868afbd96bae4e799 Mon Sep 17 00:00:00 2001 From: Damien Zammit Date: Wed, 12 Nov 2014 01:09:55 +1100 Subject: ALSA: usb-audio: Add duplex mode for Digidesign Mbox 1 and enable mixer This patch provides duplex support for the Digidesign Mbox 1 sound card and has been a work in progress for about a year. Users have confirmed on my website that previous versions of this patch have worked on the hardware and I have been testing extensively. It also enables the mixer control for providing clock source selector based on the previous patch. The sample rate has been hardcoded to 48kHz because it works better with the S/PDIF sync mode when the sample rate is locked. This is the highest rate that the device supports and no loss of functionality is observed by restricting the sample rate apart from the inability to selec a lower rate. Signed-off-by: Damien Zammit Signed-off-by: Takashi Iwai --- sound/usb/quirks-table.h | 41 ++++++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index c657752a420c..13f44fd0e930 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -2944,7 +2944,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), .data = (const struct snd_usb_audio_quirk[]){ { .ifnum = 0, - .type = QUIRK_IGNORE_INTERFACE, + .type = QUIRK_AUDIO_STANDARD_MIXER, }, { .ifnum = 1, @@ -2955,16 +2955,40 @@ YAMAHA_DEVICE(0x7010, "UB99"), .iface = 1, .altsetting = 1, .altset_idx = 1, - .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, + .attributes = 0x4, .endpoint = 0x02, - .ep_attr = 0x01, - .rates = SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000, - .rate_min = 44100, + .ep_attr = USB_ENDPOINT_XFER_ISOC | + USB_ENDPOINT_SYNC_SYNC, + .maxpacksize = 0x130, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, .rate_max = 48000, - .nr_rates = 2, + .nr_rates = 1, .rate_table = (unsigned int[]) { - 44100, 48000 + 48000 + } + } + }, + { + .ifnum = 1, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3BE, + .channels = 2, + .iface = 1, + .altsetting = 1, + .altset_idx = 1, + .attributes = 0x4, + .endpoint = 0x81, + .ep_attr = USB_ENDPOINT_XFER_ISOC | + USB_ENDPOINT_SYNC_ASYNC, + .maxpacksize = 0x130, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .nr_rates = 1, + .rate_table = (unsigned int[]) { + 48000 } } }, @@ -2972,7 +2996,6 @@ YAMAHA_DEVICE(0x7010, "UB99"), .ifnum = -1 } } - } }, -- cgit v1.2.3 From ef9566a3a1c0e46dadfa6c722e8a685ac0cea081 Mon Sep 17 00:00:00 2001 From: Chris J Arges Date: Wed, 12 Nov 2014 12:06:59 -0600 Subject: Revert "ALSA: usb-audio: Add quirk for Focusrite Scarlett This reverts commit 1762a59d8e8b5e99f6f4a0f292b40f3cacb108ba. This quirk is not needed because support for the Scarlett mixers will be added. Signed-off-by: Chris J Arges Signed-off-by: Takashi Iwai --- sound/usb/quirks-table.h | 51 ------------------------------------------------ 1 file changed, 51 deletions(-) (limited to 'sound') diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 13f44fd0e930..013cba8ee8a6 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -2667,57 +2667,6 @@ YAMAHA_DEVICE(0x7010, "UB99"), .type = QUIRK_MIDI_NOVATION } }, -{ - /* - * Focusrite Scarlett 18i6 - * - * Avoid mixer creation, which otherwise fails because some of - * the interface descriptor subtypes for interface 0 are - * unknown. That should be fixed or worked-around but this at - * least allows the device to be used successfully with a DAW - * and an external mixer. See comments below about other - * ignored interfaces. - */ - USB_DEVICE(0x1235, 0x8004), - .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { - .vendor_name = "Focusrite", - .product_name = "Scarlett 18i6", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_COMPOSITE, - .data = & (const struct snd_usb_audio_quirk[]) { - { - /* InterfaceSubClass 1 (Control Device) */ - .ifnum = 0, - .type = QUIRK_IGNORE_INTERFACE - }, - { - .ifnum = 1, - .type = QUIRK_AUDIO_STANDARD_INTERFACE - }, - { - .ifnum = 2, - .type = QUIRK_AUDIO_STANDARD_INTERFACE - }, - { - /* InterfaceSubClass 1 (Control Device) */ - .ifnum = 3, - .type = QUIRK_IGNORE_INTERFACE - }, - { - .ifnum = 4, - .type = QUIRK_MIDI_STANDARD_INTERFACE - }, - { - /* InterfaceSubClass 1 (Device Firmware Update) */ - .ifnum = 5, - .type = QUIRK_IGNORE_INTERFACE - }, - { - .ifnum = -1 - } - } - } -}, /* Access Music devices */ { -- cgit v1.2.3 From f41d6049d18694e8b3d938464432d0e51f671089 Mon Sep 17 00:00:00 2001 From: Chris J Arges Date: Wed, 12 Nov 2014 12:07:00 -0600 Subject: ALSA: usb-audio: Add private_data pointer to usb_mixer_elem_info Add a private_data pointer to usb_mixer_elem_info to allow other mixer implementations to extend the structure as necessary. Signed-off-by: Chris J Arges Signed-off-by: Takashi Iwai --- sound/usb/mixer.h | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h index 2c7b9c9c2aa6..7423f998cfb5 100644 --- a/sound/usb/mixer.h +++ b/sound/usb/mixer.h @@ -53,6 +53,7 @@ struct usb_mixer_elem_info { int cached; int cache_val[MAX_CHANNELS]; u8 initialized; + void *private_data; }; int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, -- cgit v1.2.3 From eef90451605d79a5703756505087e0ef16da9077 Mon Sep 17 00:00:00 2001 From: Chris J Arges Date: Wed, 12 Nov 2014 12:07:01 -0600 Subject: ALSA: usb-audio: make set_*_mix_values functions public Make the functions set_cur_mix_value and get_cur_mix_value accessible by files that include mixer.h. In addition make usb_mixer_elem_free accessible. This allows reuse of these functions by mixers that may require quirks. The following summarizes the renamed functions: - set_cur_mix_value -> snd_usb_set_cur_mix_value - get_cur_mix_value -> snd_usb_get_cur_mix_value - usb_mixer_elem_free -> snd_usb_mixer_elem_free Signed-off-by: Chris J Arges Signed-off-by: Takashi Iwai --- sound/usb/mixer.c | 34 +++++++++++++++++----------------- sound/usb/mixer.h | 8 ++++++++ sound/usb/mixer_quirks.c | 9 +-------- 3 files changed, 26 insertions(+), 25 deletions(-) (limited to 'sound') diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index e4aaa21baed2..14e1455ca9de 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -412,7 +412,7 @@ static inline int get_cur_mix_raw(struct usb_mixer_elem_info *cval, value); } -static int get_cur_mix_value(struct usb_mixer_elem_info *cval, +int snd_usb_get_cur_mix_value(struct usb_mixer_elem_info *cval, int channel, int index, int *value) { int err; @@ -497,7 +497,7 @@ static int set_cur_ctl_value(struct usb_mixer_elem_info *cval, return snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, validx, value); } -static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel, +int snd_usb_set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel, int index, int value) { int err; @@ -815,7 +815,7 @@ static struct usb_feature_control_info audio_feature_info[] = { }; /* private_free callback */ -static void usb_mixer_elem_free(struct snd_kcontrol *kctl) +void snd_usb_mixer_elem_free(struct snd_kcontrol *kctl) { kfree(kctl->private_data); kctl->private_data = NULL; @@ -998,7 +998,7 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval, else test -= cval->res; if (test < cval->min || test > cval->max || - set_cur_mix_value(cval, minchn, 0, test) || + snd_usb_set_cur_mix_value(cval, minchn, 0, test) || get_cur_mix_raw(cval, minchn, &check)) { cval->res = last_valid_res; break; @@ -1007,7 +1007,7 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval, break; cval->res *= 2; } - set_cur_mix_value(cval, minchn, 0, saved); + snd_usb_set_cur_mix_value(cval, minchn, 0, saved); } cval->initialized = 1; @@ -1086,7 +1086,7 @@ static int mixer_ctl_feature_get(struct snd_kcontrol *kcontrol, for (c = 0; c < MAX_CHANNELS; c++) { if (!(cval->cmask & (1 << c))) continue; - err = get_cur_mix_value(cval, c + 1, cnt, &val); + err = snd_usb_get_cur_mix_value(cval, c + 1, cnt, &val); if (err < 0) return cval->mixer->ignore_ctl_error ? 0 : err; val = get_relative_value(cval, val); @@ -1096,7 +1096,7 @@ static int mixer_ctl_feature_get(struct snd_kcontrol *kcontrol, return 0; } else { /* master channel */ - err = get_cur_mix_value(cval, 0, 0, &val); + err = snd_usb_get_cur_mix_value(cval, 0, 0, &val); if (err < 0) return cval->mixer->ignore_ctl_error ? 0 : err; val = get_relative_value(cval, val); @@ -1118,26 +1118,26 @@ static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol, for (c = 0; c < MAX_CHANNELS; c++) { if (!(cval->cmask & (1 << c))) continue; - err = get_cur_mix_value(cval, c + 1, cnt, &oval); + err = snd_usb_get_cur_mix_value(cval, c + 1, cnt, &oval); if (err < 0) return cval->mixer->ignore_ctl_error ? 0 : err; val = ucontrol->value.integer.value[cnt]; val = get_abs_value(cval, val); if (oval != val) { - set_cur_mix_value(cval, c + 1, cnt, val); + snd_usb_set_cur_mix_value(cval, c + 1, cnt, val); changed = 1; } cnt++; } } else { /* master channel */ - err = get_cur_mix_value(cval, 0, 0, &oval); + err = snd_usb_get_cur_mix_value(cval, 0, 0, &oval); if (err < 0) return cval->mixer->ignore_ctl_error ? 0 : err; val = ucontrol->value.integer.value[0]; val = get_abs_value(cval, val); if (val != oval) { - set_cur_mix_value(cval, 0, 0, val); + snd_usb_set_cur_mix_value(cval, 0, 0, val); changed = 1; } } @@ -1250,7 +1250,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, /* * If all channels in the mask are marked read-only, make the control - * read-only. set_cur_mix_value() will check the mask again and won't + * read-only. snd_usb_set_cur_mix_value() will check the mask again and won't * issue write commands to read-only channels. */ if (cval->channels == readonly_mask) @@ -1263,7 +1263,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, kfree(cval); return; } - kctl->private_free = usb_mixer_elem_free; + kctl->private_free = snd_usb_mixer_elem_free; len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)); mapped_name = len != 0; @@ -1546,7 +1546,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state, kfree(cval); return; } - kctl->private_free = usb_mixer_elem_free; + kctl->private_free = snd_usb_mixer_elem_free; len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)); if (!len) @@ -1846,7 +1846,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, kfree(cval); return -ENOMEM; } - kctl->private_free = usb_mixer_elem_free; + kctl->private_free = snd_usb_mixer_elem_free; if (check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name))) { /* nothing */ ; @@ -2526,7 +2526,7 @@ static int restore_mixer_value(struct usb_mixer_elem_info *cval) if (!(cval->cmask & (1 << c))) continue; if (cval->cached & (1 << c)) { - err = set_cur_mix_value(cval, c + 1, idx, + err = snd_usb_set_cur_mix_value(cval, c + 1, idx, cval->cache_val[idx]); if (err < 0) return err; @@ -2536,7 +2536,7 @@ static int restore_mixer_value(struct usb_mixer_elem_info *cval) } else { /* master */ if (cval->cached) { - err = set_cur_mix_value(cval, 0, 0, *cval->cache_val); + err = snd_usb_set_cur_mix_value(cval, 0, 0, *cval->cache_val); if (err < 0) return err; } diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h index 7423f998cfb5..2478a844a322 100644 --- a/sound/usb/mixer.h +++ b/sound/usb/mixer.h @@ -76,4 +76,12 @@ int snd_usb_mixer_suspend(struct usb_mixer_interface *mixer); int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume); #endif +int snd_usb_set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel, + int index, int value); + +int snd_usb_get_cur_mix_value(struct usb_mixer_elem_info *cval, + int channel, int index, int *value); + +extern void snd_usb_mixer_elem_free(struct snd_kcontrol *kctl); + #endif /* __USBMIXER_H */ diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 45203168ac6d..b8b1f48c1f50 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -52,13 +52,6 @@ struct std_mono_table { snd_kcontrol_tlv_rw_t *tlv_callback; }; -/* private_free callback */ -static void usb_mixer_elem_free(struct snd_kcontrol *kctl) -{ - kfree(kctl->private_data); - kctl->private_data = NULL; -} - /* This function allows for the creation of standard UAC controls. * See the quirks for M-Audio FTUs or Ebox-44. * If you don't want to set a TLV callback pass NULL. @@ -108,7 +101,7 @@ static int snd_create_std_mono_ctl_offset(struct usb_mixer_interface *mixer, /* Set name */ snprintf(kctl->id.name, sizeof(kctl->id.name), name); - kctl->private_free = usb_mixer_elem_free; + kctl->private_free = snd_usb_mixer_elem_free; /* set TLV */ if (tlv_callback) { -- cgit v1.2.3 From 76b188c4b370876018e3a778ec11a94a5316dbe4 Mon Sep 17 00:00:00 2001 From: Chris J Arges Date: Wed, 12 Nov 2014 12:07:02 -0600 Subject: ALSA: usb-audio: Scarlett mixer interface for 6i6, 18i6, 18i8 and 18i20 This code contains the Scarlett mixer interface code that was originally written by Tobias Hoffman and Robin Gareus. Because the device doesn't properly implement UAC2 this code adds a mixer quirk for the device. Changes from the original code include removing the metering code along with dead code and comments. Compiler warnings were fixed. The code to initialize the sampling rate was causing a crash this was fixed as discussed on the mailing list. Error, and info messages were convered to dev_err and dev_info interfaces. The custom scarlett_mixer_elem_info struct was replaced with the more generic usb_mixer_elem_info to be able to recycle more code from mixer.c. This patch also makes additional modifications based on upstream comments. Individual control creation functions are removed and a generic function is no used. Macros for function calls are removed to improve readability. Hardcoded control initialization is removed. Save to HW functionality has been removed. Strings for enums are created dynamically for the mixer. Strings used for controls are now SNDRV_CTL_ELEM_ID_NAME_MAXLEN length. Signed-off-by: Chris J Arges Signed-off-by: Takashi Iwai --- sound/usb/Makefile | 1 + sound/usb/mixer_quirks.c | 9 + sound/usb/mixer_scarlett.c | 967 +++++++++++++++++++++++++++++++++++++++++++++ sound/usb/mixer_scarlett.h | 6 + 4 files changed, 983 insertions(+) create mode 100644 sound/usb/mixer_scarlett.c create mode 100644 sound/usb/mixer_scarlett.h (limited to 'sound') diff --git a/sound/usb/Makefile b/sound/usb/Makefile index 2b92f0dcbc4c..bcee4060fd18 100644 --- a/sound/usb/Makefile +++ b/sound/usb/Makefile @@ -9,6 +9,7 @@ snd-usb-audio-objs := card.o \ helper.o \ mixer.o \ mixer_quirks.o \ + mixer_scarlett.o \ pcm.o \ proc.o \ quirks.o \ diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index b8b1f48c1f50..7b9331a17026 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -41,6 +41,7 @@ #include "usbaudio.h" #include "mixer.h" #include "mixer_quirks.h" +#include "mixer_scarlett.h" #include "helper.h" extern struct snd_kcontrol_new *snd_usb_feature_unit_ctl; @@ -1770,6 +1771,14 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) /* detection is disabled in mixer_maps.c */ err = snd_create_std_mono_table(mixer, ebox44_table); break; + + case USB_ID(0x1235, 0x8012): /* Focusrite Scarlett 6i6 */ + case USB_ID(0x1235, 0x8002): /* Focusrite Scarlett 8i6 */ + case USB_ID(0x1235, 0x8004): /* Focusrite Scarlett 18i6 */ + case USB_ID(0x1235, 0x8014): /* Focusrite Scarlett 18i8 */ + case USB_ID(0x1235, 0x800c): /* Focusrite Scarlett 18i20 */ + err = snd_scarlett_controls_create(mixer); + break; } return err; diff --git a/sound/usb/mixer_scarlett.c b/sound/usb/mixer_scarlett.c new file mode 100644 index 000000000000..a0a874507de5 --- /dev/null +++ b/sound/usb/mixer_scarlett.c @@ -0,0 +1,967 @@ +/* + * Scarlett Driver for ALSA + * + * Copyright (c) 2013 by Tobias Hoffmann + * Copyright (c) 2013 by Robin Gareus + * Copyright (c) 2002 by Takashi Iwai + * Copyright (c) 2014 by Chris J Arges + * + * Many codes borrowed from audio.c by + * Alan Cox (alan at lxorguk.ukuu.org.uk) + * Thomas Sailer (sailer at ife.ee.ethz.ch) + * + * Code cleanup: + * David Henningsson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/* + * Rewritten and extended to support more models, e.g. Scarlett 18i8. + * + * Auto-detection via UAC2 is not feasible to properly discover the vast + * majority of features. It's related to both Linux/ALSA's UAC2 as well as + * Focusrite's implementation of it. Eventually quirks may be sufficient but + * right now it's a major headache to work arount these things. + * + * NB. Neither the OSX nor the win driver provided by Focusrite performs + * discovery, they seem to operate the same as this driver. + */ + +/* Mixer Interface for the Focusrite Scarlett 18i6 audio interface. + * + * The protocol was reverse engineered by looking at communication between + * Scarlett MixControl (v 1.2.128.0) and the Focusrite(R) Scarlett 18i6 + * (firmware v305) using wireshark and usbmon in January 2013. + * Extended in July 2013. + * + * this mixer gives complete access to all features of the device: + * - change Impedance of inputs (Line-in, Mic / Instrument, Hi-Z) + * - select clock source + * - dynamic input to mixer-matrix assignment + * - 18 x 6 mixer-matrix gain stages + * - bus routing & volume control + * - automatic re-initialization on connect if device was power-cycled + * + * USB URB commands overview (bRequest = 0x01 = UAC2_CS_CUR) + * wIndex + * 0x01 Analog Input line/instrument impedance switch, wValue=0x0901 + + * channel, data=Line/Inst (2bytes) + * pad (-10dB) switch, wValue=0x0b01 + channel, data=Off/On (2bytes) + * ?? wValue=0x0803/04, ?? (2bytes) + * 0x0a Master Volume, wValue=0x0200+bus[0:all + only 1..4?] data(2bytes) + * Bus Mute/Unmute wValue=0x0100+bus[0:all + only 1..4?], data(2bytes) + * 0x28 Clock source, wValue=0x0100, data={1:int,2:spdif,3:adat} (1byte) + * 0x29 Set Sample-rate, wValue=0x0100, data=sample-rate(4bytes) + * 0x32 Mixer mux, wValue=0x0600 + mixer-channel, data=input-to-connect(2bytes) + * 0x33 Output mux, wValue=bus, data=input-to-connect(2bytes) + * 0x34 Capture mux, wValue=0...18, data=input-to-connect(2bytes) + * 0x3c Matrix Mixer gains, wValue=mixer-node data=gain(2bytes) + * ?? [sometimes](4bytes, e.g 0x000003be 0x000003bf ...03ff) + * + * USB reads: (i.e. actually issued by original software) + * 0x01 wValue=0x0901+channel (1byte!!), wValue=0x0b01+channed (1byte!!) + * 0x29 wValue=0x0100 sample-rate(4bytes) + * wValue=0x0200 ?? 1byte (only once) + * 0x2a wValue=0x0100 ?? 4bytes, sample-rate2 ?? + * + * USB reads with bRequest = 0x03 = UAC2_CS_MEM + * 0x3c wValue=0x0002 1byte: sync status (locked=1) + * wValue=0x0000 18*2byte: peak meter (inputs) + * wValue=0x0001 8(?)*2byte: peak meter (mix) + * wValue=0x0003 6*2byte: peak meter (pcm/daw) + * + * USB write with bRequest = 0x03 + * 0x3c Save settings to hardware: wValue=0x005a, data=0xa5 + * + * + * + * /--------------\ 18chn 6chn /--------------\ + * | Hardware in +--+-------\ /------+--+ ALSA PCM out | + * \--------------/ | | | | \--------------/ + * | | | | + * | v v | + * | +---------------+ | + * | \ Matrix Mux / | + * | +-----+-----+ | + * | | | + * | | 18chn | + * | v | + * | +-----------+ | + * | | Mixer | | + * | | Matrix | | + * | | | | + * | | 18x6 Gain | | + * | | stages | | + * | +-----+-----+ | + * | | | + * | | | + * | 18chn | 6chn | 6chn + * v v v + * ========================= + * +---------------+ +--—------------+ + * \ Output Mux / \ Capture Mux / + * +-----+-----+ +-----+-----+ + * | | + * | 6chn | + * v | + * +-------------+ | + * | Master Gain | | + * +------+------+ | + * | | + * | 6chn | 18chn + * | (3 stereo pairs) | + * /--------------\ | | /--------------\ + * | Hardware out |<--/ \-->| ALSA PCM in | + * \--------------/ \--------------/ + * + * + */ + +#include +#include +#include + +#include +#include +#include + +#include "usbaudio.h" +#include "mixer.h" +#include "helper.h" +#include "power.h" + +#include "mixer_scarlett.h" + +/* some gui mixers can't handle negative ctl values */ +#define SND_SCARLETT_LEVEL_BIAS 128 +#define SND_SCARLETT_MATRIX_IN_MAX 18 +#define SND_SCARLETT_CONTROLS_MAX 10 +#define SND_SCARLETT_OFFSETS_MAX 5 + +enum { + SCARLETT_OUTPUTS, + SCARLETT_SWITCH_IMPEDANCE, + SCARLETT_SWITCH_PAD, +}; + +enum { + SCARLETT_OFFSET_PCM = 0, + SCARLETT_OFFSET_ANALOG = 1, + SCARLETT_OFFSET_SPDIF = 2, + SCARLETT_OFFSET_ADAT = 3, + SCARLETT_OFFSET_MIX = 4, +}; + +struct scarlett_mixer_elem_enum_info { + int start; + int len; + int offsets[SND_SCARLETT_OFFSETS_MAX]; + char const * const *names; +}; + +struct scarlett_mixer_control { + unsigned char num; + unsigned char type; + const char *name; +}; + +struct scarlett_device_info { + int matrix_in; + int matrix_out; + int input_len; + int output_len; + + struct scarlett_mixer_elem_enum_info opt_master; + struct scarlett_mixer_elem_enum_info opt_matrix; + + /* initial values for matrix mux */ + int matrix_mux_init[SND_SCARLETT_MATRIX_IN_MAX]; + + int num_controls; /* number of items in controls */ + const struct scarlett_mixer_control controls[SND_SCARLETT_CONTROLS_MAX]; +}; + +/********************** Enum Strings *************************/ + +static const struct scarlett_mixer_elem_enum_info opt_pad = { + .start = 0, + .len = 2, + .offsets = {}, + .names = (char const * const []){ + "0dB", "-10dB" + } +}; + +static const struct scarlett_mixer_elem_enum_info opt_impedance = { + .start = 0, + .len = 2, + .offsets = {}, + .names = (char const * const []){ + "Line", "Hi-Z" + } +}; + +static const struct scarlett_mixer_elem_enum_info opt_clock = { + .start = 1, + .len = 3, + .offsets = {}, + .names = (char const * const []){ + "Internal", "SPDIF", "ADAT" + } +}; + +static const struct scarlett_mixer_elem_enum_info opt_sync = { + .start = 0, + .len = 2, + .offsets = {}, + .names = (char const * const []){ + "No Lock", "Locked" + } +}; + +static int scarlett_ctl_switch_info(struct snd_kcontrol *kctl, + struct snd_ctl_elem_info *uinfo) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = elem->channels; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int scarlett_ctl_switch_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + int i, err, val; + + for (i = 0; i < elem->channels; i++) { + err = snd_usb_get_cur_mix_value(elem, i, i, &val); + if (err < 0) + return err; + + val = !val; /* invert mute logic for mixer */ + ucontrol->value.integer.value[i] = val; + } + + return 0; +} + +static int scarlett_ctl_switch_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + int i, changed = 0; + int err, oval, val; + + for (i = 0; i < elem->channels; i++) { + err = snd_usb_get_cur_mix_value(elem, i, i, &oval); + if (err < 0) + return err; + + val = ucontrol->value.integer.value[i]; + val = !val; + if (oval != val) { + err = snd_usb_set_cur_mix_value(elem, i, i, val); + if (err < 0) + return err; + + changed = 1; + } + } + + return changed; +} + +static int scarlett_ctl_info(struct snd_kcontrol *kctl, + struct snd_ctl_elem_info *uinfo) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = elem->channels; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = (int)kctl->private_value + + SND_SCARLETT_LEVEL_BIAS; + uinfo->value.integer.step = 1; + return 0; +} + +static int scarlett_ctl_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + int i, err, val; + + for (i = 0; i < elem->channels; i++) { + err = snd_usb_get_cur_mix_value(elem, i, i, &val); + if (err < 0) + return err; + + val = clamp(val / 256, -128, (int)kctl->private_value) + + SND_SCARLETT_LEVEL_BIAS; + ucontrol->value.integer.value[i] = val; + } + + return 0; +} + +static int scarlett_ctl_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + int i, changed = 0; + int err, oval, val; + + for (i = 0; i < elem->channels; i++) { + err = snd_usb_get_cur_mix_value(elem, i, i, &oval); + if (err < 0) + return err; + + val = ucontrol->value.integer.value[i] - + SND_SCARLETT_LEVEL_BIAS; + val = val * 256; + if (oval != val) { + err = snd_usb_set_cur_mix_value(elem, i, i, val); + if (err < 0) + return err; + + changed = 1; + } + } + + return changed; +} + +static void scarlett_generate_name(int i, char *dst, int offsets[]) +{ + if (i > offsets[SCARLETT_OFFSET_MIX]) + sprintf(dst, "Mix %c", + 'A'+(i - offsets[SCARLETT_OFFSET_MIX] - 1)); + else if (i > offsets[SCARLETT_OFFSET_ADAT]) + sprintf(dst, "ADAT %d", i - offsets[SCARLETT_OFFSET_ADAT]); + else if (i > offsets[SCARLETT_OFFSET_SPDIF]) + sprintf(dst, "SPDIF %d", i - offsets[SCARLETT_OFFSET_SPDIF]); + else if (i > offsets[SCARLETT_OFFSET_ANALOG]) + sprintf(dst, "Analog %d", i - offsets[SCARLETT_OFFSET_ANALOG]); + else if (i > offsets[SCARLETT_OFFSET_PCM]) + sprintf(dst, "PCM %d", i - offsets[SCARLETT_OFFSET_PCM]); + else + sprintf(dst, "Off"); +} + +static int scarlett_ctl_enum_dynamic_info(struct snd_kcontrol *kctl, + struct snd_ctl_elem_info *uinfo) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct scarlett_mixer_elem_enum_info *opt = elem->private_data; + unsigned int items = opt->len; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = elem->channels; + uinfo->value.enumerated.items = items; + + if (uinfo->value.enumerated.item >= items) + uinfo->value.enumerated.item = items - 1; + + /* generate name dynamically based on item number and offset info */ + scarlett_generate_name(uinfo->value.enumerated.item, + uinfo->value.enumerated.name, + opt->offsets); + + return 0; +} + +static int scarlett_ctl_enum_info(struct snd_kcontrol *kctl, + struct snd_ctl_elem_info *uinfo) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct scarlett_mixer_elem_enum_info *opt = elem->private_data; + + return snd_ctl_enum_info(uinfo, elem->channels, opt->len, + (const char * const *)opt->names); +} + +static int scarlett_ctl_enum_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct scarlett_mixer_elem_enum_info *opt = elem->private_data; + int err, val; + + err = snd_usb_get_cur_mix_value(elem, 0, 0, &val); + if (err < 0) + return err; + + val = clamp(val - opt->start, 0, opt->len-1); + + ucontrol->value.enumerated.item[0] = val; + + return 0; +} + +static int scarlett_ctl_enum_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct scarlett_mixer_elem_enum_info *opt = elem->private_data; + int err, oval, val; + + err = snd_usb_get_cur_mix_value(elem, 0, 0, &oval); + if (err < 0) + return err; + + val = ucontrol->value.integer.value[0]; + val = val + opt->start; + if (val != oval) { + snd_usb_set_cur_mix_value(elem, 0, 0, val); + return 1; + } + return 0; +} + +static int scarlett_ctl_meter_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct snd_usb_audio *chip = elem->mixer->chip; + unsigned char buf[2 * MAX_CHANNELS] = {0, }; + int wValue = (elem->control << 8) | elem->idx_off; + int idx = snd_usb_ctrl_intf(chip) | (elem->id << 8); + int err; + + err = snd_usb_ctl_msg(chip->dev, + usb_rcvctrlpipe(chip->dev, 0), + UAC2_CS_MEM, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | + USB_DIR_IN, wValue, idx, buf, elem->channels); + if (err < 0) + return err; + + ucontrol->value.enumerated.item[0] = clamp((int)buf[0], 0, 1); + return 0; +} + +static struct snd_kcontrol_new usb_scarlett_ctl_switch = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = scarlett_ctl_switch_info, + .get = scarlett_ctl_switch_get, + .put = scarlett_ctl_switch_put, +}; + +static const DECLARE_TLV_DB_SCALE(db_scale_scarlett_gain, -12800, 100, 0); + +static struct snd_kcontrol_new usb_scarlett_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .name = "", + .info = scarlett_ctl_info, + .get = scarlett_ctl_get, + .put = scarlett_ctl_put, + .private_value = 6, /* max value */ + .tlv = { .p = db_scale_scarlett_gain } +}; + +static struct snd_kcontrol_new usb_scarlett_ctl_master = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .name = "", + .info = scarlett_ctl_info, + .get = scarlett_ctl_get, + .put = scarlett_ctl_put, + .private_value = 6, /* max value */ + .tlv = { .p = db_scale_scarlett_gain } +}; + +static struct snd_kcontrol_new usb_scarlett_ctl_enum = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = scarlett_ctl_enum_info, + .get = scarlett_ctl_enum_get, + .put = scarlett_ctl_enum_put, +}; + +static struct snd_kcontrol_new usb_scarlett_ctl_dynamic_enum = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = scarlett_ctl_enum_dynamic_info, + .get = scarlett_ctl_enum_get, + .put = scarlett_ctl_enum_put, +}; + +static struct snd_kcontrol_new usb_scarlett_ctl_sync = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .name = "", + .info = scarlett_ctl_enum_info, + .get = scarlett_ctl_meter_get, +}; + +static int add_new_ctl(struct usb_mixer_interface *mixer, + const struct snd_kcontrol_new *ncontrol, + int index, int offset, int num, + int val_type, int channels, const char *name, + const struct scarlett_mixer_elem_enum_info *opt, + struct usb_mixer_elem_info **elem_ret +) +{ + struct snd_kcontrol *kctl; + struct usb_mixer_elem_info *elem; + int err; + + elem = kzalloc(sizeof(*elem), GFP_KERNEL); + if (!elem) + return -ENOMEM; + + elem->mixer = mixer; + elem->control = offset; + elem->idx_off = num; + elem->id = index; + elem->val_type = val_type; + + elem->channels = channels; + + /* add scarlett_mixer_elem_enum_info struct */ + elem->private_data = (void *)opt; + + kctl = snd_ctl_new1(ncontrol, elem); + if (!kctl) { + kfree(elem); + return -ENOMEM; + } + kctl->private_free = snd_usb_mixer_elem_free; + + strlcpy(kctl->id.name, name, sizeof(kctl->id.name)); + + err = snd_ctl_add(mixer->chip->card, kctl); + if (err < 0) + return err; + + if (elem_ret) + *elem_ret = elem; + + return 0; +} + +static int add_output_ctls(struct usb_mixer_interface *mixer, + int index, const char *name, + const struct scarlett_device_info *info) +{ + int err; + char mx[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + struct usb_mixer_elem_info *elem; + + /* Add mute switch */ + snprintf(mx, sizeof(mx), "Master %d (%s) Playback Switch", + index + 1, name); + err = add_new_ctl(mixer, &usb_scarlett_ctl_switch, 0x0a, 0x01, + 2*index+1, USB_MIXER_S16, 2, mx, NULL, &elem); + if (err < 0) + return err; + + /* Add volume control and initialize to 0 */ + snprintf(mx, sizeof(mx), "Master %d (%s) Playback Volume", + index + 1, name); + err = add_new_ctl(mixer, &usb_scarlett_ctl_master, 0x0a, 0x02, + 2*index+1, USB_MIXER_S16, 2, mx, NULL, &elem); + if (err < 0) + return err; + + /* Add L channel source playback enumeration */ + snprintf(mx, sizeof(mx), "Master %dL (%s) Source Playback Enum", + index + 1, name); + err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum, 0x33, 0x00, + 2*index, USB_MIXER_S16, 1, mx, &info->opt_master, + &elem); + if (err < 0) + return err; + + /* Add R channel source playback enumeration */ + snprintf(mx, sizeof(mx), "Master %dR (%s) Source Playback Enum", + index + 1, name); + err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum, 0x33, 0x00, + 2*index+1, USB_MIXER_S16, 1, mx, &info->opt_master, + &elem); + if (err < 0) + return err; + + return 0; +} + +/********************** device-specific config *************************/ + +/* untested... */ +static struct scarlett_device_info s6i6_info = { + .matrix_in = 18, + .matrix_out = 8, + .input_len = 6, + .output_len = 6, + + .opt_master = { + .start = -1, + .len = 27, + .offsets = {0, 12, 16, 18, 18}, + .names = NULL + }, + + .opt_matrix = { + .start = -1, + .len = 19, + .offsets = {0, 12, 16, 18, 18}, + .names = NULL + }, + + .num_controls = 0, + .controls = { + { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" }, + { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone" }, + { .num = 2, .type = SCARLETT_OUTPUTS, .name = "SPDIF" }, + { .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, + { .num = 1, .type = SCARLETT_SWITCH_PAD, .name = NULL}, + { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, + { .num = 2, .type = SCARLETT_SWITCH_PAD, .name = NULL}, + { .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL}, + { .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL}, + }, + + .matrix_mux_init = { + 12, 13, 14, 15, /* Analog -> 1..4 */ + 16, 17, /* SPDIF -> 5,6 */ + 0, 1, 2, 3, 4, 5, 6, 7, /* PCM[1..12] -> 7..18 */ + 8, 9, 10, 11 + } +}; + +/* untested... */ +static struct scarlett_device_info s8i6_info = { + .matrix_in = 18, + .matrix_out = 6, + .input_len = 8, + .output_len = 6, + + .opt_master = { + .start = -1, + .len = 25, + .offsets = {0, 12, 16, 18, 18}, + .names = NULL + }, + + .opt_matrix = { + .start = -1, + .len = 19, + .offsets = {0, 12, 16, 18, 18}, + .names = NULL + }, + + .num_controls = 7, + .controls = { + { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" }, + { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone" }, + { .num = 2, .type = SCARLETT_OUTPUTS, .name = "SPDIF" }, + { .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, + { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, + { .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL}, + { .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL}, + }, + + .matrix_mux_init = { + 12, 13, 14, 15, /* Analog -> 1..4 */ + 16, 17, /* SPDIF -> 5,6 */ + 0, 1, 2, 3, 4, 5, 6, 7, /* PCM[1..12] -> 7..18 */ + 8, 9, 10, 11 + } +}; + +static struct scarlett_device_info s18i6_info = { + .matrix_in = 18, + .matrix_out = 6, + .input_len = 18, + .output_len = 6, + + .opt_master = { + .start = -1, + .len = 31, + .offsets = {0, 6, 14, 16, 24}, + .names = NULL, + }, + + .opt_matrix = { + .start = -1, + .len = 25, + .offsets = {0, 6, 14, 16, 24}, + .names = NULL, + }, + + .num_controls = 5, + .controls = { + { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" }, + { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone" }, + { .num = 2, .type = SCARLETT_OUTPUTS, .name = "SPDIF" }, + { .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, + { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, + }, + + .matrix_mux_init = { + 6, 7, 8, 9, 10, 11, 12, 13, /* Analog -> 1..8 */ + 16, 17, 18, 19, 20, 21, /* ADAT[1..6] -> 9..14 */ + 14, 15, /* SPDIF -> 15,16 */ + 0, 1 /* PCM[1,2] -> 17,18 */ + } +}; + +static struct scarlett_device_info s18i8_info = { + .matrix_in = 18, + .matrix_out = 8, + .input_len = 18, + .output_len = 8, + + .opt_master = { + .start = -1, + .len = 35, + .offsets = {0, 8, 16, 18, 26}, + .names = NULL + }, + + .opt_matrix = { + .start = -1, + .len = 27, + .offsets = {0, 8, 16, 18, 26}, + .names = NULL + }, + + .num_controls = 10, + .controls = { + { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" }, + { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone 1" }, + { .num = 2, .type = SCARLETT_OUTPUTS, .name = "Headphone 2" }, + { .num = 3, .type = SCARLETT_OUTPUTS, .name = "SPDIF" }, + { .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, + { .num = 1, .type = SCARLETT_SWITCH_PAD, .name = NULL}, + { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, + { .num = 2, .type = SCARLETT_SWITCH_PAD, .name = NULL}, + { .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL}, + { .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL}, + }, + + .matrix_mux_init = { + 8, 9, 10, 11, 12, 13, 14, 15, /* Analog -> 1..8 */ + 18, 19, 20, 21, 22, 23, /* ADAT[1..6] -> 9..14 */ + 16, 17, /* SPDIF -> 15,16 */ + 0, 1 /* PCM[1,2] -> 17,18 */ + } +}; + +static struct scarlett_device_info s18i20_info = { + .matrix_in = 18, + .matrix_out = 8, + .input_len = 18, + .output_len = 20, + + .opt_master = { + .start = -1, + .len = 47, + .offsets = {0, 20, 28, 30, 38}, + .names = NULL + }, + + .opt_matrix = { + .start = -1, + .len = 39, + .offsets = {0, 20, 28, 30, 38}, + .names = NULL + }, + + .num_controls = 10, + .controls = { + { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" }, + { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Line 3/4" }, + { .num = 2, .type = SCARLETT_OUTPUTS, .name = "Line 5/6" }, + { .num = 3, .type = SCARLETT_OUTPUTS, .name = "Line 7/8" }, + { .num = 4, .type = SCARLETT_OUTPUTS, .name = "Line 9/10" }, + { .num = 5, .type = SCARLETT_OUTPUTS, .name = "SPDIF" }, + { .num = 6, .type = SCARLETT_OUTPUTS, .name = "ADAT 1/2" }, + { .num = 7, .type = SCARLETT_OUTPUTS, .name = "ADAT 3/4" }, + { .num = 8, .type = SCARLETT_OUTPUTS, .name = "ADAT 5/6" }, + { .num = 9, .type = SCARLETT_OUTPUTS, .name = "ADAT 7/8" }, + /*{ .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, + { .num = 1, .type = SCARLETT_SWITCH_PAD, .name = NULL}, + { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, + { .num = 2, .type = SCARLETT_SWITCH_PAD, .name = NULL}, + { .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL}, + { .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL},*/ + }, + + .matrix_mux_init = { + 20, 21, 22, 23, 24, 25, 26, 27, /* Analog -> 1..8 */ + 30, 31, 32, 33, 34, 35, /* ADAT[1..6] -> 9..14 */ + 28, 29, /* SPDIF -> 15,16 */ + 0, 1 /* PCM[1,2] -> 17,18 */ + } +}; + + +static int scarlett_controls_create_generic(struct usb_mixer_interface *mixer, + struct scarlett_device_info *info) +{ + int i, err; + char mx[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + const struct scarlett_mixer_control *ctl; + struct usb_mixer_elem_info *elem; + + /* create master switch and playback volume */ + err = add_new_ctl(mixer, &usb_scarlett_ctl_switch, 0x0a, 0x01, 0, + USB_MIXER_S16, 1, "Master Playback Switch", NULL, + &elem); + if (err < 0) + return err; + + err = add_new_ctl(mixer, &usb_scarlett_ctl_master, 0x0a, 0x02, 0, + USB_MIXER_S16, 1, "Master Playback Volume", NULL, + &elem); + if (err < 0) + return err; + + /* iterate through controls in info struct and create each one */ + for (i = 0; i < info->num_controls; i++) { + ctl = &info->controls[i]; + + switch (ctl->type) { + case SCARLETT_OUTPUTS: + err = add_output_ctls(mixer, ctl->num, ctl->name, info); + if (err < 0) + return err; + break; + case SCARLETT_SWITCH_IMPEDANCE: + sprintf(mx, "Input %d Impedance Switch", ctl->num); + err = add_new_ctl(mixer, &usb_scarlett_ctl_enum, 0x01, + 0x09, ctl->num, USB_MIXER_S16, 1, mx, + &opt_impedance, &elem); + if (err < 0) + return err; + break; + case SCARLETT_SWITCH_PAD: + sprintf(mx, "Input %d Pad Switch", ctl->num); + err = add_new_ctl(mixer, &usb_scarlett_ctl_enum, 0x01, + 0x0b, ctl->num, USB_MIXER_S16, 1, mx, + &opt_pad, &elem); + if (err < 0) + return err; + break; + } + } + + return 0; +} + +/* + * Create and initialize a mixer for the Focusrite(R) Scarlett + */ +int snd_scarlett_controls_create(struct usb_mixer_interface *mixer) +{ + int err, i, o; + char mx[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + struct scarlett_device_info *info; + struct usb_mixer_elem_info *elem; + static char sample_rate_buffer[4] = { '\x80', '\xbb', '\x00', '\x00' }; + + /* only use UAC_VERSION_2 */ + if (!mixer->protocol) + return 0; + + switch (mixer->chip->usb_id) { + case USB_ID(0x1235, 0x8012): + info = &s6i6_info; + break; + case USB_ID(0x1235, 0x8002): + info = &s8i6_info; + break; + case USB_ID(0x1235, 0x8004): + info = &s18i6_info; + break; + case USB_ID(0x1235, 0x8014): + info = &s18i8_info; + break; + case USB_ID(0x1235, 0x800c): + info = &s18i20_info; + break; + default: /* device not (yet) supported */ + return -EINVAL; + } + + /* generic function to create controls */ + err = scarlett_controls_create_generic(mixer, info); + if (err < 0) + return err; + + /* setup matrix controls */ + for (i = 0; i < info->matrix_in; i++) { + snprintf(mx, sizeof(mx), "Matrix %02d Input Playback Route", + i+1); + err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum, 0x32, + 0x06, i, USB_MIXER_S16, 1, mx, + &info->opt_matrix, &elem); + if (err < 0) + return err; + + for (o = 0; o < info->matrix_out; o++) { + sprintf(mx, "Matrix %02d Mix %c Playback Volume", i+1, + o+'A'); + err = add_new_ctl(mixer, &usb_scarlett_ctl, 0x3c, 0x00, + (i << 3) + (o & 0x07), USB_MIXER_S16, + 1, mx, NULL, &elem); + if (err < 0) + return err; + + } + } + + for (i = 0; i < info->input_len; i++) { + snprintf(mx, sizeof(mx), "Input Source %02d Capture Route", + i+1); + err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum, 0x34, + 0x00, i, USB_MIXER_S16, 1, mx, + &info->opt_master, &elem); + if (err < 0) + return err; + } + + /* val_len == 1 needed here */ + err = add_new_ctl(mixer, &usb_scarlett_ctl_enum, 0x28, 0x01, 0, + USB_MIXER_U8, 1, "Sample Clock Source", + &opt_clock, &elem); + if (err < 0) + return err; + + /* val_len == 1 and UAC2_CS_MEM */ + err = add_new_ctl(mixer, &usb_scarlett_ctl_sync, 0x3c, 0x00, 2, + USB_MIXER_U8, 1, "Sample Clock Sync Status", + &opt_sync, &elem); + if (err < 0) + return err; + + /* initialize sampling rate to 48000 */ + err = snd_usb_ctl_msg(mixer->chip->dev, + usb_sndctrlpipe(mixer->chip->dev, 0), UAC2_CS_CUR, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | + USB_DIR_OUT, 0x0100, snd_usb_ctrl_intf(mixer->chip) | + (0x29 << 8), sample_rate_buffer, 4); + if (err < 0) + return err; + + return err; +} diff --git a/sound/usb/mixer_scarlett.h b/sound/usb/mixer_scarlett.h new file mode 100644 index 000000000000..19c592ab0332 --- /dev/null +++ b/sound/usb/mixer_scarlett.h @@ -0,0 +1,6 @@ +#ifndef __USB_MIXER_SCARLETT_H +#define __USB_MIXER_SCARLETT_H + +int snd_scarlett_controls_create(struct usb_mixer_interface *mixer); + +#endif /* __USB_MIXER_SCARLETT_H */ -- cgit v1.2.3 From 9547c0999e50fd624cab52f94a79f0fd27a7cb84 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 28 Oct 2014 14:22:49 -0700 Subject: ALSA: 6fire: Convert byte_rev_table uses to bitrev8 Use the inline function instead of directly indexing the array. This allows some architectures with hardware instructions for bit reversals to eliminate the array. Signed-off-by: Joe Perches Signed-off-by: Takashi Iwai --- sound/usb/6fire/firmware.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c index 3b02e54b8f6d..62c25e74f0e5 100644 --- a/sound/usb/6fire/firmware.c +++ b/sound/usb/6fire/firmware.c @@ -316,7 +316,7 @@ static int usb6fire_fw_fpga_upload( while (c != end) { for (i = 0; c != end && i < FPGA_BUFSIZE; i++, c++) - buffer[i] = byte_rev_table[(u8) *c]; + buffer[i] = bitrev8((u8)*c); ret = usb6fire_fw_fpga_write(device, buffer, i); if (ret < 0) { -- cgit v1.2.3 From 387417b56295ef93d7cb38e1721826c85dfe897c Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Fri, 14 Nov 2014 16:09:05 +0530 Subject: ALSA: ice1712: remove unneeded return statement the functions: snd_ice1712_akm4xxx_build_controls snd_ice1712_build_pro_mixer snd_ctl_add snd_ak4114_build prodigy192_ak4114_init snd_ak4113_build are all returning either 0 or a negetive error value. so we can easily remove the check for a negative value and return the value instead. Signed-off-by: Sudip Mukherjee Signed-off-by: Takashi Iwai --- sound/pci/ice1712/hoontech.c | 6 +----- sound/pci/ice1712/ice1712.c | 19 ++++++------------- sound/pci/ice1712/ice1724.c | 7 ++----- sound/pci/ice1712/juli.c | 5 +---- sound/pci/ice1712/prodigy192.c | 4 +--- sound/pci/ice1712/quartet.c | 5 +---- 6 files changed, 12 insertions(+), 34 deletions(-) (limited to 'sound') diff --git a/sound/pci/ice1712/hoontech.c b/sound/pci/ice1712/hoontech.c index 59e37c581691..a40001c1d9e8 100644 --- a/sound/pci/ice1712/hoontech.c +++ b/sound/pci/ice1712/hoontech.c @@ -309,11 +309,7 @@ static int snd_ice1712_value_init(struct snd_ice1712 *ice) return err; /* ak4524 controls */ - err = snd_ice1712_akm4xxx_build_controls(ice); - if (err < 0) - return err; - - return 0; + return snd_ice1712_akm4xxx_build_controls(ice); } static int snd_ice1712_ez8_init(struct snd_ice1712 *ice) diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index 48a0c330da24..597533490f2d 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -1295,10 +1295,7 @@ static int snd_ice1712_pcm_profi(struct snd_ice1712 *ice, int device, struct snd return err; } - err = snd_ice1712_build_pro_mixer(ice); - if (err < 0) - return err; - return 0; + return snd_ice1712_build_pro_mixer(ice); } /* @@ -1545,10 +1542,9 @@ static int snd_ice1712_ac97_mixer(struct snd_ice1712 *ice) dev_warn(ice->card->dev, "cannot initialize ac97 for consumer, skipped\n"); else { - err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_digmix_route_ac97, ice)); - if (err < 0) - return err; - return 0; + return snd_ctl_add(ice->card, + snd_ctl_new1(&snd_ice1712_mixer_digmix_route_ac97, + ice)); } } @@ -2497,11 +2493,8 @@ static int snd_ice1712_build_controls(struct snd_ice1712 *ice) err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_pro_volume_rate, ice)); if (err < 0) return err; - err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_pro_peak, ice)); - if (err < 0) - return err; - - return 0; + return snd_ctl_add(ice->card, + snd_ctl_new1(&snd_ice1712_mixer_pro_peak, ice)); } static int snd_ice1712_free(struct snd_ice1712 *ice) diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index f633e3bb4c43..ea53167081b8 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -2497,11 +2497,8 @@ static int snd_vt1724_build_controls(struct snd_ice1712 *ice) return err; } - err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_vt1724_mixer_pro_peak, ice)); - if (err < 0) - return err; - - return 0; + return snd_ctl_add(ice->card, + snd_ctl_new1(&snd_vt1724_mixer_pro_peak, ice)); } static int snd_vt1724_free(struct snd_ice1712 *ice) diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c index 7a6c0786c55c..a1536c1a7ed4 100644 --- a/sound/pci/ice1712/juli.c +++ b/sound/pci/ice1712/juli.c @@ -475,11 +475,8 @@ static int juli_add_controls(struct snd_ice1712 *ice) return err; /* only capture SPDIF over AK4114 */ - err = snd_ak4114_build(spec->ak4114, NULL, + return snd_ak4114_build(spec->ak4114, NULL, ice->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream); - if (err < 0) - return err; - return 0; } /* diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c index 1eb151aaa965..3919aed39ca0 100644 --- a/sound/pci/ice1712/prodigy192.c +++ b/sound/pci/ice1712/prodigy192.c @@ -758,10 +758,8 @@ static int prodigy192_init(struct snd_ice1712 *ice) "AK4114 initialized with status %d\n", err); } else dev_dbg(ice->card->dev, "AK4114 not found\n"); - if (err < 0) - return err; - return 0; + return err; } diff --git a/sound/pci/ice1712/quartet.c b/sound/pci/ice1712/quartet.c index d4caf9d05922..6f55e02e5c84 100644 --- a/sound/pci/ice1712/quartet.c +++ b/sound/pci/ice1712/quartet.c @@ -833,11 +833,8 @@ static int qtet_add_controls(struct snd_ice1712 *ice) if (err < 0) return err; /* only capture SPDIF over AK4113 */ - err = snd_ak4113_build(spec->ak4113, + return snd_ak4113_build(spec->ak4113, ice->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream); - if (err < 0) - return err; - return 0; } static inline int qtet_is_spdif_master(struct snd_ice1712 *ice) -- cgit v1.2.3 From b393df0145e271724fee10f93c023662f8557bb9 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Fri, 14 Nov 2014 16:09:07 +0530 Subject: ALSA: ice1712: remove unused variable buf_size was initialized with snd_pcm_lib_buffer_bytes, but never used. and so it is safe to be deleted. Signed-off-by: Sudip Mukherjee Signed-off-by: Takashi Iwai --- sound/pci/ice1712/ice1712.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index 597533490f2d..65251911cf6f 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -620,10 +620,9 @@ static int snd_ice1712_playback_ds_prepare(struct snd_pcm_substream *substream) { struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - u32 period_size, buf_size, rate, tmp, chn; + u32 period_size, rate, tmp, chn; period_size = snd_pcm_lib_period_bytes(substream) - 1; - buf_size = snd_pcm_lib_buffer_bytes(substream) - 1; tmp = 0x0064; if (snd_pcm_format_width(runtime->format) == 16) tmp &= ~0x04; -- cgit v1.2.3 From b8eca77e54525c818f35f51afb64fc13205443a3 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Fri, 14 Nov 2014 18:12:21 +0530 Subject: ALSA: ice1712: consider error value earlier we were ignoring the return value of snd_ak4114_create and always returning 0. now we are returning the actual status. revo_init is calling this function, and revo_init is checking the return value. Signed-off-by: Sudip Mukherjee Signed-off-by: Takashi Iwai --- sound/pci/ice1712/revo.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c index 1112ec1953be..1d81ae677573 100644 --- a/sound/pci/ice1712/revo.c +++ b/sound/pci/ice1712/revo.c @@ -494,11 +494,13 @@ static int ap192_ak4114_init(struct snd_ice1712 *ice) ap192_ak4114_write, ak4114_init_vals, ak4114_init_txcsb, ice, &spec->ak4114); + if (err < 0) + return err; /* AK4114 in Revo cannot detect external rate correctly. * No reason to stop capture stream due to incorrect checks */ spec->ak4114->check_flags = AK4114_CHECK_NO_RATE; - return 0; /* error ignored; it's no fatal error */ + return 0; } static int revo_init(struct snd_ice1712 *ice) -- cgit v1.2.3 From f0acd28c87ad2a5d1b40403fdd5defda2961b2a1 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 17 Nov 2014 10:44:33 +0100 Subject: ALSA: hda: Deletion of unnecessary checks before two function calls The functions kfree() and release_firmware() test whether their argument is NULL and then return immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 3 +-- sound/pci/hda/hda_intel.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index ca98f5209f8f..b2d58998dbdd 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -834,8 +834,7 @@ static void snd_hda_bus_free(struct hda_bus *bus) WARN_ON(!list_empty(&bus->codec_list)); if (bus->workq) flush_workqueue(bus->workq); - if (bus->unsol) - kfree(bus->unsol); + kfree(bus->unsol); if (bus->ops.private_free) bus->ops.private_free(bus); if (bus->workq) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 9ab1e631cb32..91fa959d05fe 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1130,8 +1130,7 @@ static int azx_free(struct azx *chip) pci_disable_device(chip->pci); kfree(chip->azx_dev); #ifdef CONFIG_SND_HDA_PATCH_LOADER - if (chip->fw) - release_firmware(chip->fw); + release_firmware(chip->fw); #endif if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { hda_display_power(false); -- cgit v1.2.3 From ae1b22658e6d3ebc6af07a225c221d84fe8cb91f Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 17 Nov 2014 11:28:02 +0100 Subject: ALSA: ice17xx: Deletion of unnecessary checks before the function call "snd_ac97_resume" The snd_ac97_resume() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Takashi Iwai --- sound/pci/ice1712/ice1712.c | 3 +-- sound/pci/ice1712/ice1724.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index 65251911cf6f..b039b46152c6 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -2878,8 +2878,7 @@ static int snd_ice1712_resume(struct device *dev) outw(ice->pm_saved_spdif_ctrl, ICEMT(ice, ROUTE_SPDOUT)); outw(ice->pm_saved_route, ICEMT(ice, ROUTE_PSDOUT03)); - if (ice->ac97) - snd_ac97_resume(ice->ac97); + snd_ac97_resume(ice->ac97); snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index ea53167081b8..d73da157ea14 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -2875,8 +2875,7 @@ static int snd_vt1724_resume(struct device *dev) outb(ice->pm_saved_spdif_cfg, ICEREG1724(ice, SPDIF_CFG)); outl(ice->pm_saved_route, ICEMT1724(ice, ROUTE_PLAYBACK)); - if (ice->ac97) - snd_ac97_resume(ice->ac97); + snd_ac97_resume(ice->ac97); snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; -- cgit v1.2.3 From 6da95e1ea8e2492530eac9c51b293226e3f4ce94 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 17 Nov 2014 12:42:16 +0100 Subject: ALSA: lola: Deletion of an unnecessary check before the function call "vfree" The vfree() function performs also input parameter validation. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Takashi Iwai --- sound/pci/lola/lola_mixer.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/lola/lola_mixer.c b/sound/pci/lola/lola_mixer.c index 782f4d8299ae..e7fe15dd5a90 100644 --- a/sound/pci/lola/lola_mixer.c +++ b/sound/pci/lola/lola_mixer.c @@ -108,8 +108,7 @@ int lola_init_pins(struct lola *chip, int dir, int *nidp) void lola_free_mixer(struct lola *chip) { - if (chip->mixer.array_saved) - vfree(chip->mixer.array_saved); + vfree(chip->mixer.array_saved); } int lola_init_mixer_widget(struct lola *chip, int nid) -- cgit v1.2.3 From c283661018e347bc72633969411974df8ec2ac92 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 17 Nov 2014 13:04:14 +0100 Subject: ALSA: hdsp: Deletion of an unnecessary check before the function call "release_firmware" The release_firmware() function tests whether its argument is NULL and then return immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdsp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 2eb8baf7b828..cf5a6c8b9a63 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -5307,8 +5307,7 @@ static int snd_hdsp_free(struct hdsp *hdsp) snd_hdsp_free_buffers(hdsp); - if (hdsp->firmware) - release_firmware(hdsp->firmware); + release_firmware(hdsp->firmware); vfree(hdsp->fw_uploaded); if (hdsp->iobase) -- cgit v1.2.3 From 1ea7a568c63a4735872fc091efbd22d2e4d9c972 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 17 Nov 2014 13:35:54 +0100 Subject: ALSA: powermac: Deletion of an unnecessary check before the function call "pci_dev_put" The pci_dev_put() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Takashi Iwai --- sound/ppc/pmac.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c index 8a431bcb056c..5a13b22748b2 100644 --- a/sound/ppc/pmac.c +++ b/sound/ppc/pmac.c @@ -887,8 +887,7 @@ static int snd_pmac_free(struct snd_pmac *chip) } } - if (chip->pdev) - pci_dev_put(chip->pdev); + pci_dev_put(chip->pdev); of_node_put(chip->node); kfree(chip); return 0; -- cgit v1.2.3 From 5f217f905bc5e9d609d0aac830736bcfc087c7f5 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 18 Nov 2014 23:59:40 +0900 Subject: ALSA: firewire-lib: fix kerneldoc errors Complete missing parameters, correct wrong reference, and add an explaination about the differences between the latest specification and our implementation. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/amdtp.h | 24 ++++++++++++++++++++++-- sound/firewire/cmp.c | 2 ++ 2 files changed, 24 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/firewire/amdtp.h b/sound/firewire/amdtp.h index 4823c08196ac..e6e8926275b0 100644 --- a/sound/firewire/amdtp.h +++ b/sound/firewire/amdtp.h @@ -23,7 +23,7 @@ * corresponds to the end of event in the packet. Out of IEC 61883. * @CIP_WRONG_DBS: Only for in-stream. The value of dbs is wrong in in-packets. * The value of data_block_quadlets is used instead of reported value. - * @SKIP_DBC_ZERO_CHECK: Only for in-stream. Packets with zero in dbc is + * @CIP_SKIP_DBC_ZERO_CHECK: Only for in-stream. Packets with zero in dbc is * skipped for detecting discontinuity. * @CIP_SKIP_INIT_DBC_CHECK: Only for in-stream. The value of dbc in first * packet is not continuous from an initial value. @@ -43,7 +43,27 @@ enum cip_flags { }; /** - * enum cip_sfc - a stream's sample rate + * enum cip_sfc - supported Sampling Frequency Codes (SFCs) + * @CIP_SFC_32000: 32,000 data blocks + * @CIP_SFC_44100: 44,100 data blocks + * @CIP_SFC_48000: 48,000 data blocks + * @CIP_SFC_88200: 88,200 data blocks + * @CIP_SFC_96000: 96,000 data blocks + * @CIP_SFC_176400: 176,400 data blocks + * @CIP_SFC_192000: 192,000 data blocks + * @CIP_SFC_COUNT: the number of supported SFCs + * + * These values are used to show nominal Sampling Frequency Code in + * Format Dependent Field (FDF) of AMDTP packet header. In IEC 61883-6:2002, + * this code means the number of events per second. Actually the code + * represents the number of data blocks transferred per second in an AMDTP + * stream. + * + * In IEC 61883-6:2005, some extensions were added to support more types of + * data such as 'One Bit LInear Audio', therefore the meaning of SFC became + * different depending on the types. + * + * Currently our implementation is compatible with IEC 61883-6:2002. */ enum cip_sfc { CIP_SFC_32000 = 0, diff --git a/sound/firewire/cmp.c b/sound/firewire/cmp.c index ba8df5a1be39..ae3bc1940efa 100644 --- a/sound/firewire/cmp.c +++ b/sound/firewire/cmp.c @@ -114,6 +114,7 @@ static int pcr_modify(struct cmp_connection *c, * cmp_connection_init - initializes a connection manager * @c: the connection manager to initialize * @unit: a unit of the target device + * @direction: input or output * @pcr_index: the index of the iPCR/oPCR on the target device */ int cmp_connection_init(struct cmp_connection *c, @@ -154,6 +155,7 @@ EXPORT_SYMBOL(cmp_connection_init); /** * cmp_connection_check_used - check connection is already esablished or not * @c: the connection manager to be checked + * @used: the pointer to store the result of checking the connection */ int cmp_connection_check_used(struct cmp_connection *c, bool *used) { -- cgit v1.2.3 From 0f32fd1900e6b972f289416dbd75e92772b630cb Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 19 Nov 2014 12:16:14 +0100 Subject: ALSA: hda/realtek - Clean up mute/mic GPIO LED handling There are a few duplicated codes handling the mute and mic-mute LEDs via GPIO pins. Let's consolidate to single helpers. Here we introduced two new fields to alc_spec, gpio_mute_led_mask and gpio_mic_led_mask, to contain the bit mask to set/clear. Also, mute_led_polarity is evaluated as well. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 81 +++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 41 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 1af917f58a70..3c29a558e7db 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -96,6 +96,8 @@ struct alc_spec { hda_nid_t cap_mute_led_nid; unsigned int gpio_led; /* used for alc269_fixup_hp_gpio_led() */ + unsigned int gpio_mute_led_mask; + unsigned int gpio_mic_led_mask; hda_nid_t headset_mic_pin; hda_nid_t headphone_mic_pin; @@ -3235,41 +3237,45 @@ static void alc269_fixup_hp_mute_led_mic2(struct hda_codec *codec, } } -/* turn on/off mute LED per vmaster hook */ -static void alc269_fixup_hp_gpio_mute_hook(void *private_data, int enabled) +/* update LED status via GPIO */ +static void alc_update_gpio_led(struct hda_codec *codec, unsigned int mask, + bool enabled) { - struct hda_codec *codec = private_data; struct alc_spec *spec = codec->spec; unsigned int oldval = spec->gpio_led; + if (spec->mute_led_polarity) + enabled = !enabled; + if (enabled) - spec->gpio_led &= ~0x08; + spec->gpio_led &= ~mask; else - spec->gpio_led |= 0x08; + spec->gpio_led |= mask; if (spec->gpio_led != oldval) snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, spec->gpio_led); } -/* turn on/off mic-mute LED per capture hook */ -static void alc269_fixup_hp_gpio_mic_mute_hook(struct hda_codec *codec, - struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +/* turn on/off mute LED via GPIO per vmaster hook */ +static void alc_fixup_gpio_mute_hook(void *private_data, int enabled) { + struct hda_codec *codec = private_data; struct alc_spec *spec = codec->spec; - unsigned int oldval = spec->gpio_led; - if (!ucontrol) - return; + alc_update_gpio_led(codec, spec->gpio_mute_led_mask, enabled); +} - if (ucontrol->value.integer.value[0] || - ucontrol->value.integer.value[1]) - spec->gpio_led &= ~0x10; - else - spec->gpio_led |= 0x10; - if (spec->gpio_led != oldval) - snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, - spec->gpio_led); +/* turn on/off mic-mute LED via GPIO per capture hook */ +static void alc_fixup_gpio_mic_mute_hook(struct hda_codec *codec, + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct alc_spec *spec = codec->spec; + + if (ucontrol) + alc_update_gpio_led(codec, spec->gpio_mic_led_mask, + ucontrol->value.integer.value[0] || + ucontrol->value.integer.value[1]); } static void alc269_fixup_hp_gpio_led(struct hda_codec *codec, @@ -3283,9 +3289,12 @@ static void alc269_fixup_hp_gpio_led(struct hda_codec *codec, }; if (action == HDA_FIXUP_ACT_PRE_PROBE) { - spec->gen.vmaster_mute.hook = alc269_fixup_hp_gpio_mute_hook; - spec->gen.cap_sync_hook = alc269_fixup_hp_gpio_mic_mute_hook; + spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook; + spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook; spec->gpio_led = 0; + spec->mute_led_polarity = 0; + spec->gpio_mute_led_mask = 0x08; + spec->gpio_mic_led_mask = 0x10; snd_hda_add_verbs(codec, gpio_init); } } @@ -3327,9 +3336,11 @@ static void alc269_fixup_hp_gpio_mic1_led(struct hda_codec *codec, }; if (action == HDA_FIXUP_ACT_PRE_PROBE) { - spec->gen.vmaster_mute.hook = alc269_fixup_hp_gpio_mute_hook; + spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook; spec->gen.cap_sync_hook = alc269_fixup_hp_cap_mic_mute_hook; spec->gpio_led = 0; + spec->mute_led_polarity = 0; + spec->gpio_mute_led_mask = 0x08; spec->cap_mute_led_nid = 0x18; snd_hda_add_verbs(codec, gpio_init); codec->power_filter = led_power_filter; @@ -3348,9 +3359,11 @@ static void alc280_fixup_hp_gpio4(struct hda_codec *codec, }; if (action == HDA_FIXUP_ACT_PRE_PROBE) { - spec->gen.vmaster_mute.hook = alc269_fixup_hp_gpio_mute_hook; + spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook; spec->gen.cap_sync_hook = alc269_fixup_hp_cap_mic_mute_hook; spec->gpio_led = 0; + spec->mute_led_polarity = 0; + spec->gpio_mute_led_mask = 0x08; spec->cap_mute_led_nid = 0x18; snd_hda_add_verbs(codec, gpio_init); codec->power_filter = led_power_filter; @@ -5624,22 +5637,6 @@ static void alc_fixup_bass_chmap(struct hda_codec *codec, } } -/* turn on/off mute LED per vmaster hook */ -static void alc662_led_gpio1_mute_hook(void *private_data, int enabled) -{ - struct hda_codec *codec = private_data; - struct alc_spec *spec = codec->spec; - unsigned int oldval = spec->gpio_led; - - if (enabled) - spec->gpio_led |= 0x01; - else - spec->gpio_led &= ~0x01; - if (spec->gpio_led != oldval) - snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, - spec->gpio_led); -} - /* avoid D3 for keeping GPIO up */ static unsigned int gpio_led_power_filter(struct hda_codec *codec, hda_nid_t nid, @@ -5662,8 +5659,10 @@ static void alc662_fixup_led_gpio1(struct hda_codec *codec, }; if (action == HDA_FIXUP_ACT_PRE_PROBE) { - spec->gen.vmaster_mute.hook = alc662_led_gpio1_mute_hook; + spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook; spec->gpio_led = 0; + spec->mute_led_polarity = 1; + spec->gpio_mute_led_mask = 0x01; snd_hda_add_verbs(codec, gpio_init); codec->power_filter = gpio_led_power_filter; } -- cgit v1.2.3 From 5aeee3424fa5926a53885b9defb593971e446d77 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Nov 2014 11:02:14 +0100 Subject: ALSA: usb-audio: Refactor ignore_ctl_error checks Introduce an internal helper macro for avoiding many open codes. The only slight behavior change is in a couple of get ballcks where the value is reset at error no matter whether ignore_ctl_error is set or not. Actually this is even safer than before. Signed-off-by: Takashi Iwai --- sound/usb/mixer.c | 39 ++++++++++++++++----------------------- 1 file changed, 16 insertions(+), 23 deletions(-) (limited to 'sound') diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index c6209ce5a430..a4fbfff63191 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -136,6 +136,10 @@ check_mapped_name(const struct usbmix_name_map *p, char *buf, int buflen) return strlcpy(buf, p->name, buflen); } +/* ignore the error value if ignore_ctl_error flag is set */ +#define filter_error(cval, err) \ + ((cval)->mixer->ignore_ctl_error ? 0 : (err)) + /* check whether the control should be ignored */ static inline int check_ignored_ctl(const struct usbmix_name_map *p) @@ -1088,7 +1092,7 @@ static int mixer_ctl_feature_get(struct snd_kcontrol *kcontrol, continue; err = snd_usb_get_cur_mix_value(cval, c + 1, cnt, &val); if (err < 0) - return cval->mixer->ignore_ctl_error ? 0 : err; + return filter_error(cval, err); val = get_relative_value(cval, val); ucontrol->value.integer.value[cnt] = val; cnt++; @@ -1098,7 +1102,7 @@ static int mixer_ctl_feature_get(struct snd_kcontrol *kcontrol, /* master channel */ err = snd_usb_get_cur_mix_value(cval, 0, 0, &val); if (err < 0) - return cval->mixer->ignore_ctl_error ? 0 : err; + return filter_error(cval, err); val = get_relative_value(cval, val); ucontrol->value.integer.value[0] = val; } @@ -1120,7 +1124,7 @@ static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol, continue; err = snd_usb_get_cur_mix_value(cval, c + 1, cnt, &oval); if (err < 0) - return cval->mixer->ignore_ctl_error ? 0 : err; + return filter_error(cval, err); val = ucontrol->value.integer.value[cnt]; val = get_abs_value(cval, val); if (oval != val) { @@ -1133,7 +1137,7 @@ static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol, /* master channel */ err = snd_usb_get_cur_mix_value(cval, 0, 0, &oval); if (err < 0) - return cval->mixer->ignore_ctl_error ? 0 : err; + return filter_error(cval, err); val = ucontrol->value.integer.value[0]; val = get_abs_value(cval, val); if (val != oval) { @@ -1628,12 +1632,10 @@ static int mixer_ctl_procunit_get(struct snd_kcontrol *kcontrol, int err, val; err = get_cur_ctl_value(cval, cval->control << 8, &val); - if (err < 0 && cval->mixer->ignore_ctl_error) { + if (err < 0) { ucontrol->value.integer.value[0] = cval->min; - return 0; + return filter_error(cval, err); } - if (err < 0) - return err; val = get_relative_value(cval, val); ucontrol->value.integer.value[0] = val; return 0; @@ -1647,11 +1649,8 @@ static int mixer_ctl_procunit_put(struct snd_kcontrol *kcontrol, int val, oval, err; err = get_cur_ctl_value(cval, cval->control << 8, &oval); - if (err < 0) { - if (cval->mixer->ignore_ctl_error) - return 0; - return err; - } + if (err < 0) + return filter_error(cval, err); val = ucontrol->value.integer.value[0]; val = get_abs_value(cval, val); if (val != oval) { @@ -1923,11 +1922,8 @@ static int mixer_ctl_selector_get(struct snd_kcontrol *kcontrol, err = get_cur_ctl_value(cval, cval->control << 8, &val); if (err < 0) { - if (cval->mixer->ignore_ctl_error) { - ucontrol->value.enumerated.item[0] = 0; - return 0; - } - return err; + ucontrol->value.enumerated.item[0] = 0; + return filter_error(cval, err); } val = get_relative_value(cval, val); ucontrol->value.enumerated.item[0] = val; @@ -1942,11 +1938,8 @@ static int mixer_ctl_selector_put(struct snd_kcontrol *kcontrol, int val, oval, err; err = get_cur_ctl_value(cval, cval->control << 8, &oval); - if (err < 0) { - if (cval->mixer->ignore_ctl_error) - return 0; - return err; - } + if (err < 0) + return filter_error(cval, err); val = ucontrol->value.enumerated.item[0]; val = get_abs_value(cval, val); if (val != oval) { -- cgit v1.2.3 From eaa8e5ef18fa9e09286482a4ded3a3cad36e44b2 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Fri, 21 Nov 2014 15:49:11 +0800 Subject: ALSA: hda/realtek - Supported HP mute Led for ALC286 New HP machine supported output mute led and input mute led. ALC286: GPIO1 to control output mute led. GPIO5 to control input mute led. Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 3c29a558e7db..3fcb7d951572 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3299,6 +3299,27 @@ static void alc269_fixup_hp_gpio_led(struct hda_codec *codec, } } +static void alc286_fixup_hp_gpio_led(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + static const struct hda_verb gpio_init[] = { + { 0x01, AC_VERB_SET_GPIO_MASK, 0x22 }, + { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x22 }, + {} + }; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook; + spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook; + spec->gpio_led = 0; + spec->mute_led_polarity = 0; + spec->gpio_mute_led_mask = 0x02; + spec->gpio_mic_led_mask = 0x20; + snd_hda_add_verbs(codec, gpio_init); + } +} + /* turn on/off mic-mute LED per capture hook */ static void alc269_fixup_hp_cap_mic_mute_hook(struct hda_codec *codec, struct snd_kcontrol *kcontrol, @@ -4238,6 +4259,7 @@ enum { ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED, ALC282_FIXUP_ASPIRE_V5_PINS, ALC280_FIXUP_HP_GPIO4, + ALC286_FIXUP_HP_GPIO_LED, }; static const struct hda_fixup alc269_fixups[] = { @@ -4705,6 +4727,10 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc280_fixup_hp_gpio4, }, + [ALC286_FIXUP_HP_GPIO_LED] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc286_fixup_hp_gpio_led, + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -4745,6 +4771,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x226a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x226b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x226e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2271, "HP", ALC286_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x229e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22b2, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22b7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), -- cgit v1.2.3 From 3360b84b8ed1f08bfb39743465b858a04492fcc3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Nov 2014 11:47:04 +0100 Subject: ALSA: usb-audio: Allow quirks to handle own resume and proc dump So far, we blindly assumed that the all usb-audio mixer elements follow the standard and apply the standard resume method for the registered elements in the id_elems[] list. However, some quirks really need the own resume and it's incomplete for now. This patch enhances the resume handling in two folds: - split some fields in struct usb_mixer_elem_info into a smaller header struct (usb_mixer_elem_list) for keeping the minimal information in the linked-list; the usb_mixer_elem_info embeds this header struct instead - add resume and dump callbacks to usb_mixer_elem_list struct to allow quirks providing the own methods For the standard mixer elements, these new callbacks are set to the standard ones as default, thus there is no functional change by this patch yet. The dump and resume callbacks are typedef'ed for ease of later patches using arrays of such function pointers. Signed-off-by: Takashi Iwai --- sound/usb/mixer.c | 156 +++++++++++++++++++++++++-------------------- sound/usb/mixer.h | 26 ++++++-- sound/usb/mixer_quirks.c | 12 +--- sound/usb/mixer_scarlett.c | 8 +-- 4 files changed, 114 insertions(+), 88 deletions(-) (limited to 'sound') diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index a4fbfff63191..41650d5b93b7 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -138,7 +138,7 @@ check_mapped_name(const struct usbmix_name_map *p, char *buf, int buflen) /* ignore the error value if ignore_ctl_error flag is set */ #define filter_error(cval, err) \ - ((cval)->mixer->ignore_ctl_error ? 0 : (err)) + ((cval)->head.mixer->ignore_ctl_error ? 0 : (err)) /* check whether the control should be ignored */ static inline int @@ -290,13 +290,13 @@ static int get_abs_value(struct usb_mixer_elem_info *cval, int val) static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret) { - struct snd_usb_audio *chip = cval->mixer->chip; + struct snd_usb_audio *chip = cval->head.mixer->chip; unsigned char buf[2]; int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1; int timeout = 10; int idx = 0, err; - err = snd_usb_autoresume(cval->mixer->chip); + err = snd_usb_autoresume(chip); if (err < 0) return -EIO; @@ -304,7 +304,7 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, while (timeout-- > 0) { if (chip->shutdown) break; - idx = snd_usb_ctrl_intf(chip) | (cval->id << 8); + idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8); if (snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), request, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, validx, idx, buf, val_len) >= val_len) { @@ -320,14 +320,14 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, out: up_read(&chip->shutdown_rwsem); - snd_usb_autosuspend(cval->mixer->chip); + snd_usb_autosuspend(chip); return err; } static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret) { - struct snd_usb_audio *chip = cval->mixer->chip; + struct snd_usb_audio *chip = cval->head.mixer->chip; unsigned char buf[2 + 3 * sizeof(__u16)]; /* enough space for one range */ unsigned char *val; int idx = 0, ret, size; @@ -351,7 +351,7 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, if (chip->shutdown) { ret = -ENODEV; } else { - idx = snd_usb_ctrl_intf(chip) | (cval->id << 8); + idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8); ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, validx, idx, buf, size); @@ -396,7 +396,7 @@ static int get_ctl_value(struct usb_mixer_elem_info *cval, int request, { validx += cval->idx_off; - return (cval->mixer->protocol == UAC_VERSION_1) ? + return (cval->head.mixer->protocol == UAC_VERSION_1) ? get_ctl_value_v1(cval, request, validx, value_ret) : get_ctl_value_v2(cval, request, validx, value_ret); } @@ -427,8 +427,8 @@ int snd_usb_get_cur_mix_value(struct usb_mixer_elem_info *cval, } err = get_cur_mix_raw(cval, channel, value); if (err < 0) { - if (!cval->mixer->ignore_ctl_error) - usb_audio_dbg(cval->mixer->chip, + if (!cval->head.mixer->ignore_ctl_error) + usb_audio_dbg(cval->head.mixer->chip, "cannot get current value for control %d ch %d: err = %d\n", cval->control, channel, err); return err; @@ -445,13 +445,13 @@ int snd_usb_get_cur_mix_value(struct usb_mixer_elem_info *cval, int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, int request, int validx, int value_set) { - struct snd_usb_audio *chip = cval->mixer->chip; + struct snd_usb_audio *chip = cval->head.mixer->chip; unsigned char buf[2]; int idx = 0, val_len, err, timeout = 10; validx += cval->idx_off; - if (cval->mixer->protocol == UAC_VERSION_1) { + if (cval->head.mixer->protocol == UAC_VERSION_1) { val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1; } else { /* UAC_VERSION_2 */ /* audio class v2 controls are always 2 bytes in size */ @@ -476,7 +476,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, while (timeout-- > 0) { if (chip->shutdown) break; - idx = snd_usb_ctrl_intf(chip) | (cval->id << 8); + idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8); if (snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), request, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, @@ -510,7 +510,7 @@ int snd_usb_set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel, cval->ch_readonly & (1 << (channel - 1)); if (read_only) { - usb_audio_dbg(cval->mixer->chip, + usb_audio_dbg(cval->head.mixer->chip, "%s(): channel %d of control %d is read_only\n", __func__, channel, cval->control); return 0; @@ -569,10 +569,10 @@ static int check_matrix_bitmap(unsigned char *bmap, * if failed, give up and free the control instance. */ -int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer, +int snd_usb_mixer_add_control(struct usb_mixer_elem_list *list, struct snd_kcontrol *kctl) { - struct usb_mixer_elem_info *cval = kctl->private_data; + struct usb_mixer_interface *mixer = list->mixer; int err; while (snd_ctl_find_id(mixer->chip->card, &kctl->id)) @@ -582,9 +582,9 @@ int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer, err); return err; } - cval->elem_id = &kctl->id; - cval->next_id_elem = mixer->id_elems[cval->id]; - mixer->id_elems[cval->id] = cval; + list->kctl = kctl; + list->next_id_elem = mixer->id_elems[list->id]; + mixer->id_elems[list->id] = list; return 0; } @@ -833,7 +833,7 @@ void snd_usb_mixer_elem_free(struct snd_kcontrol *kctl) static void volume_control_quirks(struct usb_mixer_elem_info *cval, struct snd_kcontrol *kctl) { - struct snd_usb_audio *chip = cval->mixer->chip; + struct snd_usb_audio *chip = cval->head.mixer->chip; switch (chip->usb_id) { case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */ case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C600 */ @@ -958,10 +958,10 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval, } if (get_ctl_value(cval, UAC_GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 || get_ctl_value(cval, UAC_GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) { - usb_audio_err(cval->mixer->chip, + usb_audio_err(cval->head.mixer->chip, "%d:%d: cannot get min/max values for control %d (id %d)\n", - cval->id, snd_usb_ctrl_intf(cval->mixer->chip), - cval->control, cval->id); + cval->head.id, snd_usb_ctrl_intf(cval->head.mixer->chip), + cval->control, cval->head.id); return -EINVAL; } if (get_ctl_value(cval, UAC_GET_RES, @@ -1065,7 +1065,7 @@ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol, kcontrol->vd[0].access &= ~(SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK); - snd_ctl_notify(cval->mixer->chip->card, + snd_ctl_notify(cval->head.mixer->chip->card, SNDRV_CTL_EVENT_MASK_INFO, &kcontrol->id); } @@ -1235,8 +1235,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, cval = kzalloc(sizeof(*cval), GFP_KERNEL); if (!cval) return; - cval->mixer = state->mixer; - cval->id = unitid; + snd_usb_mixer_elem_init_std(&cval->head, state->mixer, unitid); cval->control = control; cval->cmask = ctl_mask; cval->val_type = audio_feature_info[control-1].type; @@ -1347,14 +1346,14 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, range); usb_audio_warn(state->chip, "[%d] FU [%s] ch = %d, val = %d/%d/%d", - cval->id, kctl->id.name, cval->channels, + cval->head.id, kctl->id.name, cval->channels, cval->min, cval->max, cval->res); } usb_audio_dbg(state->chip, "[%d] FU [%s] ch = %d, val = %d/%d/%d\n", - cval->id, kctl->id.name, cval->channels, + cval->head.id, kctl->id.name, cval->channels, cval->min, cval->max, cval->res); - snd_usb_mixer_add_control(state->mixer, kctl); + snd_usb_mixer_add_control(&cval->head, kctl); } /* @@ -1528,8 +1527,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state, if (!cval) return; - cval->mixer = state->mixer; - cval->id = unitid; + snd_usb_mixer_elem_init_std(&cval->head, state->mixer, unitid); cval->control = in_ch + 1; /* based on 1 */ cval->val_type = USB_MIXER_S16; for (i = 0; i < num_outs; i++) { @@ -1561,8 +1559,8 @@ static void build_mixer_unit_ctl(struct mixer_build *state, append_ctl_name(kctl, " Volume"); usb_audio_dbg(state->chip, "[%d] MU [%s] ch = %d, val = %d/%d\n", - cval->id, kctl->id.name, cval->channels, cval->min, cval->max); - snd_usb_mixer_add_control(state->mixer, kctl); + cval->head.id, kctl->id.name, cval->channels, cval->min, cval->max); + snd_usb_mixer_add_control(&cval->head, kctl); } /* @@ -1812,8 +1810,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, cval = kzalloc(sizeof(*cval), GFP_KERNEL); if (!cval) return -ENOMEM; - cval->mixer = state->mixer; - cval->id = unitid; + snd_usb_mixer_elem_init_std(&cval->head, state->mixer, unitid); cval->control = valinfo->control; cval->val_type = valinfo->val_type; cval->channels = 1; @@ -1866,10 +1863,10 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, usb_audio_dbg(state->chip, "[%d] PU [%s] ch = %d, val = %d/%d\n", - cval->id, kctl->id.name, cval->channels, + cval->head.id, kctl->id.name, cval->channels, cval->min, cval->max); - err = snd_usb_mixer_add_control(state->mixer, kctl); + err = snd_usb_mixer_add_control(&cval->head, kctl); if (err < 0) return err; } @@ -2016,8 +2013,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, cval = kzalloc(sizeof(*cval), GFP_KERNEL); if (!cval) return -ENOMEM; - cval->mixer = state->mixer; - cval->id = unitid; + snd_usb_mixer_elem_init_std(&cval->head, state->mixer, unitid); cval->val_type = USB_MIXER_U8; cval->channels = 1; cval->min = 1; @@ -2088,11 +2084,8 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, } usb_audio_dbg(state->chip, "[%d] SU [%s] items = %d\n", - cval->id, kctl->id.name, desc->bNrInPins); - if ((err = snd_usb_mixer_add_control(state->mixer, kctl)) < 0) - return err; - - return 0; + cval->head.id, kctl->id.name, desc->bNrInPins); + return snd_usb_mixer_add_control(&cval->head, kctl); } /* @@ -2237,25 +2230,21 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid) { - struct usb_mixer_elem_info *info; + struct usb_mixer_elem_list *list; - for (info = mixer->id_elems[unitid]; info; info = info->next_id_elem) + for (list = mixer->id_elems[unitid]; list; list = list->next_id_elem) snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE, - info->elem_id); + &list->kctl->id); } static void snd_usb_mixer_dump_cval(struct snd_info_buffer *buffer, - int unitid, - struct usb_mixer_elem_info *cval) + struct usb_mixer_elem_list *list) { + struct usb_mixer_elem_info *cval = (struct usb_mixer_elem_info *)list; static char *val_types[] = {"BOOLEAN", "INV_BOOLEAN", "S8", "U8", "S16", "U16"}; - snd_iprintf(buffer, " Unit: %i\n", unitid); - if (cval->elem_id) - snd_iprintf(buffer, " Control: name=\"%s\", index=%i\n", - cval->elem_id->name, cval->elem_id->index); snd_iprintf(buffer, " Info: id=%i, control=%i, cmask=0x%x, " - "channels=%i, type=\"%s\"\n", cval->id, + "channels=%i, type=\"%s\"\n", cval->head.id, cval->control, cval->cmask, cval->channels, val_types[cval->val_type]); snd_iprintf(buffer, " Volume: min=%i, max=%i, dBmin=%i, dBmax=%i\n", @@ -2267,7 +2256,7 @@ static void snd_usb_mixer_proc_read(struct snd_info_entry *entry, { struct snd_usb_audio *chip = entry->private_data; struct usb_mixer_interface *mixer; - struct usb_mixer_elem_info *cval; + struct usb_mixer_elem_list *list; int unitid; list_for_each_entry(mixer, &chip->mixer_list, list) { @@ -2277,9 +2266,17 @@ static void snd_usb_mixer_proc_read(struct snd_info_entry *entry, mixer->ignore_ctl_error); snd_iprintf(buffer, "Card: %s\n", chip->card->longname); for (unitid = 0; unitid < MAX_ID_ELEMS; unitid++) { - for (cval = mixer->id_elems[unitid]; cval; - cval = cval->next_id_elem) - snd_usb_mixer_dump_cval(buffer, unitid, cval); + for (list = mixer->id_elems[unitid]; list; + list = list->next_id_elem) { + snd_iprintf(buffer, " Unit: %i\n", list->id); + if (list->kctl) + snd_iprintf(buffer, + " Control: name=\"%s\", index=%i\n", + list->kctl->id.name, + list->kctl->id.index); + if (list->dump) + list->dump(buffer, list); + } } } } @@ -2287,7 +2284,7 @@ static void snd_usb_mixer_proc_read(struct snd_info_entry *entry, static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer, int attribute, int value, int index) { - struct usb_mixer_elem_info *info; + struct usb_mixer_elem_list *list; __u8 unitid = (index >> 8) & 0xff; __u8 control = (value >> 8) & 0xff; __u8 channel = value & 0xff; @@ -2299,7 +2296,13 @@ static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer, return; } - for (info = mixer->id_elems[unitid]; info; info = info->next_id_elem) { + for (list = mixer->id_elems[unitid]; list; list = list->next_id_elem) { + struct usb_mixer_elem_info *info; + + if (!list->kctl) + continue; + + info = (struct usb_mixer_elem_info *)list; if (info->control != control) continue; @@ -2312,7 +2315,7 @@ static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer, info->cached = 0; snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE, - info->elem_id); + &info->head.kctl->id); break; case UAC2_CS_RANGE: @@ -2510,8 +2513,9 @@ int snd_usb_mixer_suspend(struct usb_mixer_interface *mixer) return 0; } -static int restore_mixer_value(struct usb_mixer_elem_info *cval) +static int restore_mixer_value(struct usb_mixer_elem_list *list) { + struct usb_mixer_elem_info *cval = (struct usb_mixer_elem_info *)list; int c, err, idx; if (cval->cmask) { @@ -2541,19 +2545,19 @@ static int restore_mixer_value(struct usb_mixer_elem_info *cval) int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume) { - struct usb_mixer_elem_info *cval; + struct usb_mixer_elem_list *list; int id, err; - /* FIXME: any mixer quirks? */ - if (reset_resume) { /* restore cached mixer values */ for (id = 0; id < MAX_ID_ELEMS; id++) { - for (cval = mixer->id_elems[id]; cval; - cval = cval->next_id_elem) { - err = restore_mixer_value(cval); - if (err < 0) - return err; + for (list = mixer->id_elems[id]; list; + list = list->next_id_elem) { + if (list->resume) { + err = list->resume(list); + if (err < 0) + return err; + } } } } @@ -2561,3 +2565,15 @@ int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume) return snd_usb_mixer_activate(mixer); } #endif + +void snd_usb_mixer_elem_init_std(struct usb_mixer_elem_list *list, + struct usb_mixer_interface *mixer, + int unitid) +{ + list->mixer = mixer; + list->id = unitid; + list->dump = snd_usb_mixer_dump_cval; +#ifdef CONFIG_PM + list->resume = restore_mixer_value; +#endif +} diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h index 2478a844a322..0fe87b7c7f00 100644 --- a/sound/usb/mixer.h +++ b/sound/usb/mixer.h @@ -1,6 +1,8 @@ #ifndef __USBMIXER_H #define __USBMIXER_H +#include + struct usb_mixer_interface { struct snd_usb_audio *chip; struct usb_host_interface *hostif; @@ -8,7 +10,7 @@ struct usb_mixer_interface { unsigned int ignore_ctl_error; struct urb *urb; /* array[MAX_ID_ELEMS], indexed by unit id */ - struct usb_mixer_elem_info **id_elems; + struct usb_mixer_elem_list **id_elems; /* the usb audio specification version this interface complies to */ int protocol; @@ -36,11 +38,21 @@ enum { USB_MIXER_U16, }; -struct usb_mixer_elem_info { +typedef void (*usb_mixer_elem_dump_func_t)(struct snd_info_buffer *buffer, + struct usb_mixer_elem_list *list); +typedef int (*usb_mixer_elem_resume_func_t)(struct usb_mixer_elem_list *elem); + +struct usb_mixer_elem_list { struct usb_mixer_interface *mixer; - struct usb_mixer_elem_info *next_id_elem; /* list of controls with same id */ - struct snd_ctl_elem_id *elem_id; + struct usb_mixer_elem_list *next_id_elem; /* list of controls with same id */ + struct snd_kcontrol *kctl; unsigned int id; + usb_mixer_elem_dump_func_t dump; + usb_mixer_elem_resume_func_t resume; +}; + +struct usb_mixer_elem_info { + struct usb_mixer_elem_list head; unsigned int control; /* CS or ICN (high byte) */ unsigned int cmask; /* channel mask bitmap: 0 = master */ unsigned int idx_off; /* Control index offset */ @@ -65,9 +77,13 @@ void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid); int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, int request, int validx, int value_set); -int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer, +int snd_usb_mixer_add_control(struct usb_mixer_elem_list *list, struct snd_kcontrol *kctl); +void snd_usb_mixer_elem_init_std(struct usb_mixer_elem_list *list, + struct usb_mixer_interface *mixer, + int unitid); + int snd_usb_mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, unsigned int size, unsigned int __user *_tlv); diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 8b55c0667f60..88a408cdddbd 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -69,7 +69,6 @@ static int snd_create_std_mono_ctl_offset(struct usb_mixer_interface *mixer, const char *name, snd_kcontrol_tlv_rw_t *tlv_callback) { - int err; struct usb_mixer_elem_info *cval; struct snd_kcontrol *kctl; @@ -77,8 +76,7 @@ static int snd_create_std_mono_ctl_offset(struct usb_mixer_interface *mixer, if (!cval) return -ENOMEM; - cval->id = unitid; - cval->mixer = mixer; + snd_usb_mixer_elem_init_std(&cval->head, mixer, unitid); cval->val_type = val_type; cval->channels = 1; cval->control = control; @@ -112,11 +110,7 @@ static int snd_create_std_mono_ctl_offset(struct usb_mixer_interface *mixer, SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; } /* Add control to mixer */ - err = snd_usb_mixer_add_control(mixer, kctl); - if (err < 0) - return err; - - return 0; + return snd_usb_mixer_add_control(&cval->head, kctl); } static int snd_create_std_mono_ctl(struct usb_mixer_interface *mixer, @@ -1206,7 +1200,7 @@ void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, int unitid = 12; /* SamleRate ExtensionUnit ID */ list_for_each_entry(mixer, &chip->mixer_list, list) { - cval = mixer->id_elems[unitid]; + cval = (struct usb_mixer_elem_info *)mixer->id_elems[unitid]; if (cval) { snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, cval->control << 8, diff --git a/sound/usb/mixer_scarlett.c b/sound/usb/mixer_scarlett.c index a0a874507de5..92dba35660b3 100644 --- a/sound/usb/mixer_scarlett.c +++ b/sound/usb/mixer_scarlett.c @@ -436,10 +436,10 @@ static int scarlett_ctl_meter_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) { struct usb_mixer_elem_info *elem = kctl->private_data; - struct snd_usb_audio *chip = elem->mixer->chip; + struct snd_usb_audio *chip = elem->head.mixer->chip; unsigned char buf[2 * MAX_CHANNELS] = {0, }; int wValue = (elem->control << 8) | elem->idx_off; - int idx = snd_usb_ctrl_intf(chip) | (elem->id << 8); + int idx = snd_usb_ctrl_intf(chip) | (elem->head.id << 8); int err; err = snd_usb_ctl_msg(chip->dev, @@ -528,10 +528,10 @@ static int add_new_ctl(struct usb_mixer_interface *mixer, if (!elem) return -ENOMEM; - elem->mixer = mixer; + elem->head.mixer = mixer; elem->control = offset; elem->idx_off = num; - elem->id = index; + elem->head.id = index; elem->val_type = val_type; elem->channels = channels; -- cgit v1.2.3 From 9cf3689bfe0784b6f6afb301bece95d3fc3eeb64 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Nov 2014 12:58:51 +0100 Subject: ALSA: usb-audio: Add audigy2nx resume support Rewrite the code to handle LEDs on audigy2nx and co for supporting the proper resume. A new internal helper function add_single_ctl_with_resume() is introduced to manage the usb_mixer_elem_list more easily. Also while we're at it, move audigy2nx_leds[] in usb_mixer_interface struct into the private_value of each kctl, too. Signed-off-by: Takashi Iwai --- sound/usb/mixer.h | 1 - sound/usb/mixer_quirks.c | 148 +++++++++++++++++++++++++++++------------------ 2 files changed, 92 insertions(+), 57 deletions(-) (limited to 'sound') diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h index 0fe87b7c7f00..0b3740ea6614 100644 --- a/sound/usb/mixer.h +++ b/sound/usb/mixer.h @@ -23,7 +23,6 @@ struct usb_mixer_interface { struct usb_ctrlrequest *rc_setup_packet; u8 rc_buffer[6]; - u8 audigy2nx_leds[3]; u8 xonar_u1_status; }; diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 88a408cdddbd..41cacf889c98 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -144,6 +144,32 @@ static int snd_create_std_mono_table(struct usb_mixer_interface *mixer, return 0; } +static int add_single_ctl_with_resume(struct usb_mixer_interface *mixer, + int id, + usb_mixer_elem_resume_func_t resume, + const struct snd_kcontrol_new *knew, + struct usb_mixer_elem_list **listp) +{ + struct usb_mixer_elem_list *list; + struct snd_kcontrol *kctl; + + list = kzalloc(sizeof(*list), GFP_KERNEL); + if (!list) + return -ENOMEM; + if (listp) + *listp = list; + list->mixer = mixer; + list->id = id; + list->resume = resume; + kctl = snd_ctl_new1(knew, list); + if (!kctl) { + kfree(list); + return -ENOMEM; + } + kctl->private_free = snd_usb_mixer_elem_free; + return snd_usb_mixer_add_control(list, kctl); +} + /* * Sound Blaster remote control configuration * @@ -271,84 +297,90 @@ static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) static int snd_audigy2nx_led_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); - int index = kcontrol->private_value; - - ucontrol->value.integer.value[0] = mixer->audigy2nx_leds[index]; + ucontrol->value.integer.value[0] = kcontrol->private_value >> 8; return 0; } -static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int snd_audigy2nx_led_update(struct usb_mixer_interface *mixer, + int value, int index) { - struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); - int index = kcontrol->private_value; - int value = ucontrol->value.integer.value[0]; - int err, changed; + struct snd_usb_audio *chip = mixer->chip; + int err; - if (value > 1) - return -EINVAL; - changed = value != mixer->audigy2nx_leds[index]; - down_read(&mixer->chip->shutdown_rwsem); - if (mixer->chip->shutdown) { + down_read(&chip->shutdown_rwsem); + if (chip->shutdown) { err = -ENODEV; goto out; } - if (mixer->chip->usb_id == USB_ID(0x041e, 0x3042)) - err = snd_usb_ctl_msg(mixer->chip->dev, - usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, + if (chip->usb_id == USB_ID(0x041e, 0x3042)) + err = snd_usb_ctl_msg(chip->dev, + usb_sndctrlpipe(chip->dev, 0), 0x24, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, !value, 0, NULL, 0); /* USB X-Fi S51 Pro */ - if (mixer->chip->usb_id == USB_ID(0x041e, 0x30df)) - err = snd_usb_ctl_msg(mixer->chip->dev, - usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, + if (chip->usb_id == USB_ID(0x041e, 0x30df)) + err = snd_usb_ctl_msg(chip->dev, + usb_sndctrlpipe(chip->dev, 0), 0x24, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, !value, 0, NULL, 0); else - err = snd_usb_ctl_msg(mixer->chip->dev, - usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, + err = snd_usb_ctl_msg(chip->dev, + usb_sndctrlpipe(chip->dev, 0), 0x24, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, value, index + 2, NULL, 0); out: - up_read(&mixer->chip->shutdown_rwsem); - if (err < 0) - return err; - mixer->audigy2nx_leds[index] = value; - return changed; + up_read(&chip->shutdown_rwsem); + return err; } -static struct snd_kcontrol_new snd_audigy2nx_controls[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "CMSS LED Switch", - .info = snd_audigy2nx_led_info, - .get = snd_audigy2nx_led_get, - .put = snd_audigy2nx_led_put, - .private_value = 0, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Power LED Switch", - .info = snd_audigy2nx_led_info, - .get = snd_audigy2nx_led_get, - .put = snd_audigy2nx_led_put, - .private_value = 1, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Dolby Digital LED Switch", - .info = snd_audigy2nx_led_info, - .get = snd_audigy2nx_led_get, - .put = snd_audigy2nx_led_put, - .private_value = 2, - }, +static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); + struct usb_mixer_interface *mixer = list->mixer; + int index = kcontrol->private_value & 0xff; + int value = ucontrol->value.integer.value[0]; + int old_value = kcontrol->private_value >> 8; + int err; + + if (value > 1) + return -EINVAL; + if (value == old_value) + return 0; + kcontrol->private_value = (value << 8) | index; + err = snd_audigy2nx_led_update(mixer, value, index); + return err < 0 ? err : 1; +} + +static int snd_audigy2nx_led_resume(struct usb_mixer_elem_list *list) +{ + int priv_value = list->kctl->private_value; + + return snd_audigy2nx_led_update(list->mixer, priv_value >> 8, + priv_value & 0xff); +} + +/* name and private_value are set dynamically */ +static struct snd_kcontrol_new snd_audigy2nx_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .info = snd_audigy2nx_led_info, + .get = snd_audigy2nx_led_get, + .put = snd_audigy2nx_led_put, +}; + +static const char * const snd_audigy2nx_led_names[] = { + "CMSS LED Switch", + "Power LED Switch", + "Dolby Digital LED Switch", }; static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer) { int i, err; - for (i = 0; i < ARRAY_SIZE(snd_audigy2nx_controls); ++i) { + for (i = 0; i < ARRAY_SIZE(snd_audigy2nx_led_names); ++i) { + struct snd_kcontrol_new knew; + /* USB X-Fi S51 doesn't have a CMSS LED */ if ((mixer->chip->usb_id == USB_ID(0x041e, 0x3042)) && i == 0) continue; @@ -361,12 +393,16 @@ static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer) mixer->chip->usb_id == USB_ID(0x041e, 0x30df) || mixer->chip->usb_id == USB_ID(0x041e, 0x3048))) break; - err = snd_ctl_add(mixer->chip->card, - snd_ctl_new1(&snd_audigy2nx_controls[i], mixer)); + + knew = snd_audigy2nx_control; + knew.name = snd_audigy2nx_led_names[i]; + knew.private_value = (1 << 8) | i; /* LED on as default */ + err = add_single_ctl_with_resume(mixer, 0, + snd_audigy2nx_led_resume, + &knew, NULL); if (err < 0) return err; } - mixer->audigy2nx_leds[1] = 1; /* Power LED is on by default */ return 0; } -- cgit v1.2.3 From 5f503ee9e270f8251ba9024bafa8d698050066cb Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Nov 2014 16:11:37 +0100 Subject: ALSA: usb-audio: Add Emu0204 channel switch resume support Similar as the previous fix, this adds the proper resume support to Emu0202 "Front Jack Channels" enum mixer element. Signed-off-by: Takashi Iwai --- sound/usb/mixer_quirks.c | 84 ++++++++++++++++++++++++++---------------------- 1 file changed, 46 insertions(+), 38 deletions(-) (limited to 'sound') diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 41cacf889c98..f2b1c0d8ccd1 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -473,63 +473,71 @@ static int snd_emu0204_ch_switch_get(struct snd_kcontrol *kcontrol, return 0; } -static int snd_emu0204_ch_switch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int snd_emu0204_ch_switch_update(struct usb_mixer_interface *mixer, + int value) { - struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); - unsigned int value = ucontrol->value.enumerated.item[0]; - int err, changed; + struct snd_usb_audio *chip = mixer->chip; + int err; unsigned char buf[2]; - if (value > 1) - return -EINVAL; - - buf[0] = 0x01; - buf[1] = value ? 0x02 : 0x01; - - changed = value != kcontrol->private_value; - down_read(&mixer->chip->shutdown_rwsem); + down_read(&chip->shutdown_rwsem); if (mixer->chip->shutdown) { err = -ENODEV; goto out; } - err = snd_usb_ctl_msg(mixer->chip->dev, - usb_sndctrlpipe(mixer->chip->dev, 0), UAC_SET_CUR, + + buf[0] = 0x01; + buf[1] = value ? 0x02 : 0x01; + err = snd_usb_ctl_msg(chip->dev, + usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, 0x0400, 0x0e00, buf, 2); out: - up_read(&mixer->chip->shutdown_rwsem); - if (err < 0) - return err; + up_read(&chip->shutdown_rwsem); + return err; +} + +static int snd_emu0204_ch_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); + struct usb_mixer_interface *mixer = list->mixer; + unsigned int value = ucontrol->value.enumerated.item[0]; + int err; + + if (value > 1) + return -EINVAL; + + if (value == kcontrol->private_value) + return 0; + kcontrol->private_value = value; - return changed; + err = snd_emu0204_ch_switch_update(mixer, value); + return err < 0 ? err : 1; } +static int snd_emu0204_ch_switch_resume(struct usb_mixer_elem_list *list) +{ + return snd_emu0204_ch_switch_update(list->mixer, + list->kctl->private_value); +} -static struct snd_kcontrol_new snd_emu0204_controls[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Front Jack Channels", - .info = snd_emu0204_ch_switch_info, - .get = snd_emu0204_ch_switch_get, - .put = snd_emu0204_ch_switch_put, - .private_value = 0, - }, +static struct snd_kcontrol_new snd_emu0204_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Front Jack Channels", + .info = snd_emu0204_ch_switch_info, + .get = snd_emu0204_ch_switch_get, + .put = snd_emu0204_ch_switch_put, + .private_value = 0, }; static int snd_emu0204_controls_create(struct usb_mixer_interface *mixer) { - int i, err; - - for (i = 0; i < ARRAY_SIZE(snd_emu0204_controls); ++i) { - err = snd_ctl_add(mixer->chip->card, - snd_ctl_new1(&snd_emu0204_controls[i], mixer)); - if (err < 0) - return err; - } - - return 0; + return add_single_ctl_with_resume(mixer, 0, + snd_emu0204_ch_switch_resume, + &snd_emu0204_control, NULL); } + /* ASUS Xonar U1 / U3 controls */ static int snd_xonar_u1_switch_get(struct snd_kcontrol *kcontrol, -- cgit v1.2.3 From 2bfb14c3b8fbc787ff4478f9d77ecee78cb922fe Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Nov 2014 16:18:15 +0100 Subject: ALSA: usb-audio: Add Xonar U1 resume support This time it's about Xonar U1: add the proper resume support for "Digital Playback Switch" element. Also, the status is moved into kcontrol private_value from usb_mixer_interface struct field. One more cut. Signed-off-by: Takashi Iwai --- sound/usb/mixer.h | 2 -- sound/usb/mixer_quirks.c | 66 ++++++++++++++++++++++++++++-------------------- 2 files changed, 38 insertions(+), 30 deletions(-) (limited to 'sound') diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h index 0b3740ea6614..d3268f0ee2b3 100644 --- a/sound/usb/mixer.h +++ b/sound/usb/mixer.h @@ -22,8 +22,6 @@ struct usb_mixer_interface { struct urb *rc_urb; struct usb_ctrlrequest *rc_setup_packet; u8 rc_buffer[6]; - - u8 xonar_u1_status; }; #define MAX_CHANNELS 16 /* max logical channels */ diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index f2b1c0d8ccd1..4afcf096ebb2 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -543,38 +543,52 @@ static int snd_emu0204_controls_create(struct usb_mixer_interface *mixer) static int snd_xonar_u1_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); - - ucontrol->value.integer.value[0] = !!(mixer->xonar_u1_status & 0x02); + ucontrol->value.integer.value[0] = !!(kcontrol->private_value & 0x02); return 0; } +static int snd_xonar_u1_switch_update(struct usb_mixer_interface *mixer, + unsigned char status) +{ + struct snd_usb_audio *chip = mixer->chip; + int err; + + down_read(&chip->shutdown_rwsem); + if (chip->shutdown) + err = -ENODEV; + else + err = snd_usb_ctl_msg(chip->dev, + usb_sndctrlpipe(chip->dev, 0), 0x08, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, + 50, 0, &status, 1); + up_read(&chip->shutdown_rwsem); + return err; +} + static int snd_xonar_u1_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); + struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); u8 old_status, new_status; - int err, changed; + int err; - old_status = mixer->xonar_u1_status; + old_status = kcontrol->private_value; if (ucontrol->value.integer.value[0]) new_status = old_status | 0x02; else new_status = old_status & ~0x02; - changed = new_status != old_status; - down_read(&mixer->chip->shutdown_rwsem); - if (mixer->chip->shutdown) - err = -ENODEV; - else - err = snd_usb_ctl_msg(mixer->chip->dev, - usb_sndctrlpipe(mixer->chip->dev, 0), 0x08, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, - 50, 0, &new_status, 1); - up_read(&mixer->chip->shutdown_rwsem); - if (err < 0) - return err; - mixer->xonar_u1_status = new_status; - return changed; + if (new_status == old_status) + return 0; + + kcontrol->private_value = new_status; + err = snd_xonar_u1_switch_update(list->mixer, new_status); + return err < 0 ? err : 1; +} + +static int snd_xonar_u1_switch_resume(struct usb_mixer_elem_list *list) +{ + return snd_xonar_u1_switch_update(list->mixer, + list->kctl->private_value); } static struct snd_kcontrol_new snd_xonar_u1_output_switch = { @@ -583,18 +597,14 @@ static struct snd_kcontrol_new snd_xonar_u1_output_switch = { .info = snd_ctl_boolean_mono_info, .get = snd_xonar_u1_switch_get, .put = snd_xonar_u1_switch_put, + .private_value = 0x05, }; static int snd_xonar_u1_controls_create(struct usb_mixer_interface *mixer) { - int err; - - err = snd_ctl_add(mixer->chip->card, - snd_ctl_new1(&snd_xonar_u1_output_switch, mixer)); - if (err < 0) - return err; - mixer->xonar_u1_status = 0x05; - return 0; + return add_single_ctl_with_resume(mixer, 0, + snd_xonar_u1_switch_resume, + &snd_xonar_u1_output_switch, NULL); } /* Digidesign Mbox 1 clock source switch (internal/spdif) */ -- cgit v1.2.3 From 25a9a4f91b909822fa07cbc9939c99a8c67d8960 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Nov 2014 16:31:35 +0100 Subject: ALSA: usb-audio: Add Digidesign Mbox 1 resume support Again another quirk fix, just convert to usb_mixer_elem_list with the resume callback for Mbox 1 stuff. Signed-off-by: Takashi Iwai --- sound/usb/mixer_quirks.c | 52 +++++++++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 23 deletions(-) (limited to 'sound') diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 4afcf096ebb2..f7ad2078c0cf 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -616,29 +616,12 @@ static int snd_mbox1_switch_get(struct snd_kcontrol *kctl, return 0; } -static int snd_mbox1_switch_put(struct snd_kcontrol *kctl, - struct snd_ctl_elem_value *ucontrol) +static int snd_mbox1_switch_update(struct usb_mixer_interface *mixer, int val) { - struct snd_usb_audio *chip; - struct usb_mixer_interface *mixer; + struct snd_usb_audio *chip = mixer->chip; int err; - bool cur_val, new_val; unsigned char buff[3]; - cur_val = kctl->private_value; - new_val = ucontrol->value.enumerated.item[0]; - - mixer = snd_kcontrol_chip(kctl); - if (snd_BUG_ON(!mixer)) - return -EINVAL; - - chip = mixer->chip; - if (snd_BUG_ON(!chip)) - return -EINVAL; - - if (cur_val == new_val) - return 0; - down_read(&chip->shutdown_rwsem); if (chip->shutdown) { err = -ENODEV; @@ -668,7 +651,7 @@ static int snd_mbox1_switch_put(struct snd_kcontrol *kctl, * while S/PDIF sync is enabled and confusing * this configuration. */ - if (new_val == 0) { + if (val == 0) { buff[0] = 0x80; buff[1] = 0xbb; buff[2] = 0x00; @@ -697,10 +680,27 @@ static int snd_mbox1_switch_put(struct snd_kcontrol *kctl, USB_RECIP_ENDPOINT, 0x100, 0x2, buff, 3); if (err < 0) goto err; - kctl->private_value = new_val; err: up_read(&chip->shutdown_rwsem); + return err; +} + +static int snd_mbox1_switch_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl); + struct usb_mixer_interface *mixer = list->mixer; + int err; + bool cur_val, new_val; + + cur_val = kctl->private_value; + new_val = ucontrol->value.enumerated.item[0]; + if (cur_val == new_val) + return 0; + + kctl->private_value = new_val; + err = snd_mbox1_switch_update(mixer, new_val); return err < 0 ? err : 1; } @@ -715,6 +715,11 @@ static int snd_mbox1_switch_info(struct snd_kcontrol *kcontrol, return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); } +static int snd_mbox1_switch_resume(struct usb_mixer_elem_list *list) +{ + return snd_mbox1_switch_update(list->mixer, list->kctl->private_value); +} + static struct snd_kcontrol_new snd_mbox1_switch = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Clock Source", @@ -728,8 +733,9 @@ static struct snd_kcontrol_new snd_mbox1_switch = { static int snd_mbox1_create_sync_switch(struct usb_mixer_interface *mixer) { - return snd_ctl_add(mixer->chip->card, - snd_ctl_new1(&snd_mbox1_switch, mixer)); + return add_single_ctl_with_resume(mixer, 0, + snd_mbox1_switch_resume, + &snd_mbox1_switch, NULL); } /* Native Instruments device quirks */ -- cgit v1.2.3 From da6d276957ea56b9514aa5c8d885edf22f0b3e65 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Nov 2014 16:59:47 +0100 Subject: ALSA: usb-audio: Add resume support for Native Instruments controls The changes at this time are a bit more wider than previous ones. Firstly, the NI controls didn't cache the values, so I had to implement the caching. It's stored in bit 24 of private_value. In addition to that, the initial values have to be read from registers. Signed-off-by: Takashi Iwai --- sound/usb/mixer_quirks.c | 99 +++++++++++++++++++++++++----------------------- 1 file changed, 52 insertions(+), 47 deletions(-) (limited to 'sound') diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index f7ad2078c0cf..e11b4f3e1215 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -742,64 +742,68 @@ static int snd_mbox1_create_sync_switch(struct usb_mixer_interface *mixer) #define _MAKE_NI_CONTROL(bRequest,wIndex) ((bRequest) << 16 | (wIndex)) -static int snd_nativeinstruments_control_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int snd_ni_control_init_val(struct usb_mixer_interface *mixer, + struct snd_kcontrol *kctl) { - struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); struct usb_device *dev = mixer->chip->dev; - u8 bRequest = (kcontrol->private_value >> 16) & 0xff; - u16 wIndex = kcontrol->private_value & 0xffff; - u8 tmp; - int ret; - - down_read(&mixer->chip->shutdown_rwsem); - if (mixer->chip->shutdown) - ret = -ENODEV; - else - ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0, wIndex, - &tmp, sizeof(tmp)); - up_read(&mixer->chip->shutdown_rwsem); + unsigned int pval = kctl->private_value; + u8 value; + int err; - if (ret < 0) { + err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), + (pval >> 16) & 0xff, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + 0, pval & 0xffff, &value, 1); + if (err < 0) { dev_err(&dev->dev, - "unable to issue vendor read request (ret = %d)", ret); - return ret; + "unable to issue vendor read request (ret = %d)", err); + return err; } - ucontrol->value.integer.value[0] = tmp; - + kctl->private_value |= (value << 24); return 0; } -static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol, +static int snd_nativeinstruments_control_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); - struct usb_device *dev = mixer->chip->dev; - u8 bRequest = (kcontrol->private_value >> 16) & 0xff; - u16 wIndex = kcontrol->private_value & 0xffff; - u16 wValue = ucontrol->value.integer.value[0]; - int ret; + ucontrol->value.integer.value[0] = kcontrol->private_value >> 24; + return 0; +} - down_read(&mixer->chip->shutdown_rwsem); - if (mixer->chip->shutdown) - ret = -ENODEV; +static int snd_ni_update_cur_val(struct usb_mixer_elem_list *list) +{ + struct snd_usb_audio *chip = list->mixer->chip; + unsigned int pval = list->kctl->private_value; + int err; + + down_read(&chip->shutdown_rwsem); + if (chip->shutdown) + err = -ENODEV; else - ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), bRequest, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, - wValue, wIndex, - NULL, 0, 1000); - up_read(&mixer->chip->shutdown_rwsem); + err = usb_control_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), + (pval >> 16) & 0xff, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + pval >> 24, pval & 0xffff, NULL, 0, 1000); + up_read(&chip->shutdown_rwsem); + return err; +} - if (ret < 0) { - dev_err(&dev->dev, - "unable to issue vendor write request (ret = %d)", ret); - return ret; - } +static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); + u8 oldval = (kcontrol->private_value >> 24) & 0xff; + u8 newval = ucontrol->value.integer.value[0]; + int err; - return 0; + if (oldval == newval) + return 0; + + kcontrol->private_value &= ~(0xff << 24); + kcontrol->private_value |= newval; + err = snd_ni_update_cur_val(list); + return err < 0 ? err : 1; } static struct snd_kcontrol_new snd_nativeinstruments_ta6_mixers[] = { @@ -870,16 +874,17 @@ static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer, }; for (i = 0; i < count; i++) { - struct snd_kcontrol *c; + struct usb_mixer_elem_list *list; template.name = kc[i].name; template.private_value = kc[i].private_value; - c = snd_ctl_new1(&template, mixer); - err = snd_ctl_add(mixer->chip->card, c); - + err = add_single_ctl_with_resume(mixer, 0, + snd_ni_update_cur_val, + &template, &list); if (err < 0) break; + snd_ni_control_init_val(mixer, list->kctl); } return err; -- cgit v1.2.3 From 0b4e9cfcef055a1be9bee5a47262e9cbcf17e8cd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Nov 2014 17:37:40 +0100 Subject: ALSA: usb-audio: Add resume support for FTU controls A few FTU mixer controls have the own value handling, so they have to be rewritten to follow the support for resume callbacks. This ended up in a fair amount of refactoring. Its own struct is now removed, instead the values are embedded in kctl private_value totally. Signed-off-by: Takashi Iwai --- sound/usb/mixer_quirks.c | 194 +++++++++++++---------------------------------- 1 file changed, 54 insertions(+), 140 deletions(-) (limited to 'sound') diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index e11b4f3e1215..fcb7ae5131a9 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -892,14 +892,6 @@ static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer, /* M-Audio FastTrack Ultra quirks */ /* FTU Effect switch (also used by C400/C600) */ -struct snd_ftu_eff_switch_priv_val { - struct usb_mixer_interface *mixer; - int cached_value; - int is_cached; - int bUnitID; - int validx; -}; - static int snd_ftu_eff_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -911,138 +903,77 @@ static int snd_ftu_eff_switch_info(struct snd_kcontrol *kcontrol, return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); } -static int snd_ftu_eff_switch_get(struct snd_kcontrol *kctl, - struct snd_ctl_elem_value *ucontrol) +static int snd_ftu_eff_switch_init(struct usb_mixer_interface *mixer, + struct snd_kcontrol *kctl) { - struct snd_usb_audio *chip; - struct usb_mixer_interface *mixer; - struct snd_ftu_eff_switch_priv_val *pval; + struct usb_device *dev = mixer->chip->dev; + unsigned int pval = kctl->private_value; int err; unsigned char value[2]; - int id, validx; - - const int val_len = 2; value[0] = 0x00; value[1] = 0x00; - pval = (struct snd_ftu_eff_switch_priv_val *) - kctl->private_value; + err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, + pval & 0xff00, + snd_usb_ctrl_intf(mixer->chip) | ((pval & 0xff) << 8), + value, 2); + if (err < 0) + return err; - if (pval->is_cached) { - ucontrol->value.enumerated.item[0] = pval->cached_value; - return 0; - } + kctl->private_value |= value[0] << 24; + return 0; +} - mixer = (struct usb_mixer_interface *) pval->mixer; - if (snd_BUG_ON(!mixer)) - return -EINVAL; +static int snd_ftu_eff_switch_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.enumerated.item[0] = kctl->private_value >> 24; + return 0; +} - chip = (struct snd_usb_audio *) mixer->chip; - if (snd_BUG_ON(!chip)) - return -EINVAL; +static int snd_ftu_eff_switch_update(struct usb_mixer_elem_list *list) +{ + struct snd_usb_audio *chip = list->mixer->chip; + unsigned int pval = list->kctl->private_value; + unsigned char value[2]; + int err; - id = pval->bUnitID; - validx = pval->validx; + value[0] = pval >> 24; + value[1] = 0; - down_read(&mixer->chip->shutdown_rwsem); - if (mixer->chip->shutdown) + down_read(&chip->shutdown_rwsem); + if (chip->shutdown) err = -ENODEV; else err = snd_usb_ctl_msg(chip->dev, - usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR, - USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - validx << 8, snd_usb_ctrl_intf(chip) | (id << 8), - value, val_len); - up_read(&mixer->chip->shutdown_rwsem); - if (err < 0) - return err; - - ucontrol->value.enumerated.item[0] = value[0]; - pval->cached_value = value[0]; - pval->is_cached = 1; - - return 0; + usb_sndctrlpipe(chip->dev, 0), + UAC_SET_CUR, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, + pval & 0xff00, + snd_usb_ctrl_intf(chip) | ((pval & 0xff) << 8), + value, 2); + up_read(&chip->shutdown_rwsem); + return err; } static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) { - struct snd_usb_audio *chip; - struct snd_ftu_eff_switch_priv_val *pval; - - struct usb_mixer_interface *mixer; - int changed, cur_val, err, new_val; - unsigned char value[2]; - int id, validx; - - const int val_len = 2; - - changed = 0; + struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl); + unsigned int pval = list->kctl->private_value; + int cur_val, err, new_val; - pval = (struct snd_ftu_eff_switch_priv_val *) - kctl->private_value; - cur_val = pval->cached_value; + cur_val = pval >> 24; new_val = ucontrol->value.enumerated.item[0]; + if (cur_val == new_val) + return 0; - mixer = (struct usb_mixer_interface *) pval->mixer; - if (snd_BUG_ON(!mixer)) - return -EINVAL; - - chip = (struct snd_usb_audio *) mixer->chip; - if (snd_BUG_ON(!chip)) - return -EINVAL; - - id = pval->bUnitID; - validx = pval->validx; - - if (!pval->is_cached) { - /* Read current value */ - down_read(&mixer->chip->shutdown_rwsem); - if (mixer->chip->shutdown) - err = -ENODEV; - else - err = snd_usb_ctl_msg(chip->dev, - usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR, - USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - validx << 8, snd_usb_ctrl_intf(chip) | (id << 8), - value, val_len); - up_read(&mixer->chip->shutdown_rwsem); - if (err < 0) - return err; - - cur_val = value[0]; - pval->cached_value = cur_val; - pval->is_cached = 1; - } - /* update value if needed */ - if (cur_val != new_val) { - value[0] = new_val; - value[1] = 0; - down_read(&mixer->chip->shutdown_rwsem); - if (mixer->chip->shutdown) - err = -ENODEV; - else - err = snd_usb_ctl_msg(chip->dev, - usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR, - USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, - validx << 8, snd_usb_ctrl_intf(chip) | (id << 8), - value, val_len); - up_read(&mixer->chip->shutdown_rwsem); - if (err < 0) - return err; - - pval->cached_value = new_val; - pval->is_cached = 1; - changed = 1; - } - - return changed; -} - -static void kctl_private_value_free(struct snd_kcontrol *kctl) -{ - kfree((void *)kctl->private_value); + kctl->private_value &= ~(0xff << 24); + kctl->private_value |= new_val << 24; + err = snd_ftu_eff_switch_update(list); + return err < 0 ? err : 1; } static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer, @@ -1057,33 +988,16 @@ static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer, .get = snd_ftu_eff_switch_get, .put = snd_ftu_eff_switch_put }; - + struct usb_mixer_elem_list *list; int err; - struct snd_kcontrol *kctl; - struct snd_ftu_eff_switch_priv_val *pval; - - pval = kzalloc(sizeof(*pval), GFP_KERNEL); - if (!pval) - return -ENOMEM; - - pval->cached_value = 0; - pval->is_cached = 0; - pval->mixer = mixer; - pval->bUnitID = bUnitID; - pval->validx = validx; - template.private_value = (unsigned long) pval; - kctl = snd_ctl_new1(&template, mixer->chip); - if (!kctl) { - kfree(pval); - return -ENOMEM; - } - - kctl->private_free = kctl_private_value_free; - err = snd_ctl_add(mixer->chip->card, kctl); + err = add_single_ctl_with_resume(mixer, bUnitID, + snd_ftu_eff_switch_update, + &template, &list); if (err < 0) return err; - + list->kctl->private_value = (validx << 8) | bUnitID; + snd_ftu_eff_switch_init(mixer, list->kctl); return 0; } -- cgit v1.2.3 From 288673beae6cbd8198be94284adbaeb5cba7dbda Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Nov 2014 18:06:17 +0100 Subject: ALSA: usb-audio: Add resume support for MicroII SPDIF ctls Like the previous fixes, the mixer accessors are converted to use usb_mixer_elem_list objects. In addition, the proper shutdown check are put in get and put callbacks. Signed-off-by: Takashi Iwai --- sound/usb/mixer_quirks.c | 135 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 93 insertions(+), 42 deletions(-) (limited to 'sound') diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index fcb7ae5131a9..dc9df007d3e3 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -1509,7 +1509,8 @@ static int snd_microii_spdif_info(struct snd_kcontrol *kcontrol, static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); + struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); + struct snd_usb_audio *chip = list->mixer->chip; int err; struct usb_interface *iface; struct usb_host_interface *alts; @@ -1517,17 +1518,23 @@ static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol, unsigned char data[3]; int rate; + down_read(&chip->shutdown_rwsem); + if (chip->shutdown) { + err = -ENODEV; + goto end; + } + ucontrol->value.iec958.status[0] = kcontrol->private_value & 0xff; ucontrol->value.iec958.status[1] = (kcontrol->private_value >> 8) & 0xff; ucontrol->value.iec958.status[2] = 0x00; /* use known values for that card: interface#1 altsetting#1 */ - iface = usb_ifnum_to_if(mixer->chip->dev, 1); + iface = usb_ifnum_to_if(chip->dev, 1); alts = &iface->altsetting[1]; ep = get_endpoint(alts, 0)->bEndpointAddress; - err = snd_usb_ctl_msg(mixer->chip->dev, - usb_rcvctrlpipe(mixer->chip->dev, 0), + err = snd_usb_ctl_msg(chip->dev, + usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR, USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN, UAC_EP_CS_ATTR_SAMPLE_RATE << 8, @@ -1542,22 +1549,27 @@ static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol, IEC958_AES3_CON_FS_48000 : IEC958_AES3_CON_FS_44100; err = 0; -end: + end: + up_read(&chip->shutdown_rwsem); return err; } -static int snd_microii_spdif_default_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int snd_microii_spdif_default_update(struct usb_mixer_elem_list *list) { - struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); - int err; + struct snd_usb_audio *chip = list->mixer->chip; + unsigned int pval = list->kctl->private_value; u8 reg; - unsigned long priv_backup = kcontrol->private_value; + int err; + + down_read(&chip->shutdown_rwsem); + if (chip->shutdown) { + err = -ENODEV; + goto end; + } - reg = ((ucontrol->value.iec958.status[1] & 0x0f) << 4) | - (ucontrol->value.iec958.status[0] & 0x0f); - err = snd_usb_ctl_msg(mixer->chip->dev, - usb_sndctrlpipe(mixer->chip->dev, 0), + reg = ((pval >> 4) & 0xf0) | (pval & 0x0f); + err = snd_usb_ctl_msg(chip->dev, + usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, reg, @@ -1567,15 +1579,10 @@ static int snd_microii_spdif_default_put(struct snd_kcontrol *kcontrol, if (err < 0) goto end; - kcontrol->private_value &= 0xfffff0f0; - kcontrol->private_value |= (ucontrol->value.iec958.status[1] & 0x0f) << 8; - kcontrol->private_value |= (ucontrol->value.iec958.status[0] & 0x0f); - - reg = (ucontrol->value.iec958.status[0] & IEC958_AES0_NONAUDIO) ? - 0xa0 : 0x20; - reg |= (ucontrol->value.iec958.status[1] >> 4) & 0x0f; - err = snd_usb_ctl_msg(mixer->chip->dev, - usb_sndctrlpipe(mixer->chip->dev, 0), + reg = (pval & IEC958_AES0_NONAUDIO) ? 0xa0 : 0x20; + reg |= (pval >> 12) & 0x0f; + err = snd_usb_ctl_msg(chip->dev, + usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, reg, @@ -1585,16 +1592,36 @@ static int snd_microii_spdif_default_put(struct snd_kcontrol *kcontrol, if (err < 0) goto end; - kcontrol->private_value &= 0xffff0fff; - kcontrol->private_value |= (ucontrol->value.iec958.status[1] & 0xf0) << 8; + end: + up_read(&chip->shutdown_rwsem); + return err; +} + +static int snd_microii_spdif_default_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); + unsigned int pval, pval_old; + int err; + + pval = pval_old = kcontrol->private_value; + pval &= 0xfffff0f0; + pval |= (ucontrol->value.iec958.status[1] & 0x0f) << 8; + pval |= (ucontrol->value.iec958.status[0] & 0x0f); + + pval &= 0xffff0fff; + pval |= (ucontrol->value.iec958.status[1] & 0xf0) << 8; /* The frequency bits in AES3 cannot be set via register access. */ /* Silently ignore any bits from the request that cannot be set. */ - err = (priv_backup != kcontrol->private_value); -end: - return err; + if (pval == pval_old) + return 0; + + kcontrol->private_value = pval; + err = snd_microii_spdif_default_update(list); + return err < 0 ? err : 1; } static int snd_microii_spdif_mask_get(struct snd_kcontrol *kcontrol, @@ -1616,15 +1643,20 @@ static int snd_microii_spdif_switch_get(struct snd_kcontrol *kcontrol, return 0; } -static int snd_microii_spdif_switch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int snd_microii_spdif_switch_update(struct usb_mixer_elem_list *list) { - struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); + struct snd_usb_audio *chip = list->mixer->chip; + u8 reg = list->kctl->private_value; int err; - u8 reg = ucontrol->value.integer.value[0] ? 0x28 : 0x2a; - err = snd_usb_ctl_msg(mixer->chip->dev, - usb_sndctrlpipe(mixer->chip->dev, 0), + down_read(&chip->shutdown_rwsem); + if (chip->shutdown) { + err = -ENODEV; + goto end; + } + + err = snd_usb_ctl_msg(chip->dev, + usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, reg, @@ -1632,15 +1664,27 @@ static int snd_microii_spdif_switch_put(struct snd_kcontrol *kcontrol, NULL, 0); - if (!err) { - err = (reg != (kcontrol->private_value & 0x0ff)); - if (err) - kcontrol->private_value = reg; - } - + end: + up_read(&chip->shutdown_rwsem); return err; } +static int snd_microii_spdif_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); + u8 reg; + int err; + + reg = ucontrol->value.integer.value[0] ? 0x28 : 0x2a; + if (reg != list->kctl->private_value) + return 0; + + kcontrol->private_value = reg; + err = snd_microii_spdif_switch_update(list); + return err < 0 ? err : 1; +} + static struct snd_kcontrol_new snd_microii_mixer_spdif[] = { { .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -1670,10 +1714,17 @@ static struct snd_kcontrol_new snd_microii_mixer_spdif[] = { static int snd_microii_controls_create(struct usb_mixer_interface *mixer) { int err, i; + static usb_mixer_elem_resume_func_t resume_funcs[] = { + snd_microii_spdif_default_update, + NULL, + snd_microii_spdif_switch_update + }; for (i = 0; i < ARRAY_SIZE(snd_microii_mixer_spdif); ++i) { - err = snd_ctl_add(mixer->chip->card, - snd_ctl_new1(&snd_microii_mixer_spdif[i], mixer)); + err = add_single_ctl_with_resume(mixer, 0, + resume_funcs[i], + &snd_microii_mixer_spdif[i], + NULL); if (err < 0) return err; } -- cgit v1.2.3 From b61f90eac1ff9d1b30497e611aba4651d4066706 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 20 Nov 2014 17:20:46 +0100 Subject: ALSA: usb-audio: Add resume support for Scarlett mixers Scarlett driver uses almost compatible usb_mixer_elem_info struct, so we just need to add a couple of simple resume callbacks to handle them accordingly. Signed-off-by: Takashi Iwai --- sound/usb/mixer_scarlett.c | 65 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 51 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/usb/mixer_scarlett.c b/sound/usb/mixer_scarlett.c index 92dba35660b3..9109652b88b9 100644 --- a/sound/usb/mixer_scarlett.c +++ b/sound/usb/mixer_scarlett.c @@ -285,6 +285,19 @@ static int scarlett_ctl_switch_put(struct snd_kcontrol *kctl, return changed; } +static int scarlett_ctl_resume(struct usb_mixer_elem_list *list) +{ + struct usb_mixer_elem_info *elem = + container_of(list, struct usb_mixer_elem_info, head); + int i; + + for (i = 0; i < elem->channels; i++) + if (elem->cached & (1 << i)) + snd_usb_set_cur_mix_value(elem, i, i, + elem->cache_val[i]); + return 0; +} + static int scarlett_ctl_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) { @@ -432,6 +445,16 @@ static int scarlett_ctl_enum_put(struct snd_kcontrol *kctl, return 0; } +static int scarlett_ctl_enum_resume(struct usb_mixer_elem_list *list) +{ + struct usb_mixer_elem_info *elem = + container_of(list, struct usb_mixer_elem_info, head); + + if (elem->cached) + snd_usb_set_cur_mix_value(elem, 0, 0, *elem->cache_val); + return 0; +} + static int scarlett_ctl_meter_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) { @@ -514,6 +537,7 @@ static struct snd_kcontrol_new usb_scarlett_ctl_sync = { static int add_new_ctl(struct usb_mixer_interface *mixer, const struct snd_kcontrol_new *ncontrol, + usb_mixer_elem_resume_func_t resume, int index, int offset, int num, int val_type, int channels, const char *name, const struct scarlett_mixer_elem_enum_info *opt, @@ -529,6 +553,7 @@ static int add_new_ctl(struct usb_mixer_interface *mixer, return -ENOMEM; elem->head.mixer = mixer; + elem->head.resume = resume; elem->control = offset; elem->idx_off = num; elem->head.id = index; @@ -548,7 +573,7 @@ static int add_new_ctl(struct usb_mixer_interface *mixer, strlcpy(kctl->id.name, name, sizeof(kctl->id.name)); - err = snd_ctl_add(mixer->chip->card, kctl); + err = snd_usb_mixer_add_control(&elem->head, kctl); if (err < 0) return err; @@ -569,7 +594,8 @@ static int add_output_ctls(struct usb_mixer_interface *mixer, /* Add mute switch */ snprintf(mx, sizeof(mx), "Master %d (%s) Playback Switch", index + 1, name); - err = add_new_ctl(mixer, &usb_scarlett_ctl_switch, 0x0a, 0x01, + err = add_new_ctl(mixer, &usb_scarlett_ctl_switch, + scarlett_ctl_resume, 0x0a, 0x01, 2*index+1, USB_MIXER_S16, 2, mx, NULL, &elem); if (err < 0) return err; @@ -577,7 +603,8 @@ static int add_output_ctls(struct usb_mixer_interface *mixer, /* Add volume control and initialize to 0 */ snprintf(mx, sizeof(mx), "Master %d (%s) Playback Volume", index + 1, name); - err = add_new_ctl(mixer, &usb_scarlett_ctl_master, 0x0a, 0x02, + err = add_new_ctl(mixer, &usb_scarlett_ctl_master, + scarlett_ctl_resume, 0x0a, 0x02, 2*index+1, USB_MIXER_S16, 2, mx, NULL, &elem); if (err < 0) return err; @@ -585,7 +612,8 @@ static int add_output_ctls(struct usb_mixer_interface *mixer, /* Add L channel source playback enumeration */ snprintf(mx, sizeof(mx), "Master %dL (%s) Source Playback Enum", index + 1, name); - err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum, 0x33, 0x00, + err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum, + scarlett_ctl_enum_resume, 0x33, 0x00, 2*index, USB_MIXER_S16, 1, mx, &info->opt_master, &elem); if (err < 0) @@ -594,7 +622,8 @@ static int add_output_ctls(struct usb_mixer_interface *mixer, /* Add R channel source playback enumeration */ snprintf(mx, sizeof(mx), "Master %dR (%s) Source Playback Enum", index + 1, name); - err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum, 0x33, 0x00, + err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum, + scarlett_ctl_enum_resume, 0x33, 0x00, 2*index+1, USB_MIXER_S16, 1, mx, &info->opt_master, &elem); if (err < 0) @@ -824,13 +853,15 @@ static int scarlett_controls_create_generic(struct usb_mixer_interface *mixer, struct usb_mixer_elem_info *elem; /* create master switch and playback volume */ - err = add_new_ctl(mixer, &usb_scarlett_ctl_switch, 0x0a, 0x01, 0, + err = add_new_ctl(mixer, &usb_scarlett_ctl_switch, + scarlett_ctl_resume, 0x0a, 0x01, 0, USB_MIXER_S16, 1, "Master Playback Switch", NULL, &elem); if (err < 0) return err; - err = add_new_ctl(mixer, &usb_scarlett_ctl_master, 0x0a, 0x02, 0, + err = add_new_ctl(mixer, &usb_scarlett_ctl_master, + scarlett_ctl_resume, 0x0a, 0x02, 0, USB_MIXER_S16, 1, "Master Playback Volume", NULL, &elem); if (err < 0) @@ -848,7 +879,8 @@ static int scarlett_controls_create_generic(struct usb_mixer_interface *mixer, break; case SCARLETT_SWITCH_IMPEDANCE: sprintf(mx, "Input %d Impedance Switch", ctl->num); - err = add_new_ctl(mixer, &usb_scarlett_ctl_enum, 0x01, + err = add_new_ctl(mixer, &usb_scarlett_ctl_enum, + scarlett_ctl_enum_resume, 0x01, 0x09, ctl->num, USB_MIXER_S16, 1, mx, &opt_impedance, &elem); if (err < 0) @@ -856,7 +888,8 @@ static int scarlett_controls_create_generic(struct usb_mixer_interface *mixer, break; case SCARLETT_SWITCH_PAD: sprintf(mx, "Input %d Pad Switch", ctl->num); - err = add_new_ctl(mixer, &usb_scarlett_ctl_enum, 0x01, + err = add_new_ctl(mixer, &usb_scarlett_ctl_enum, + scarlett_ctl_enum_resume, 0x01, 0x0b, ctl->num, USB_MIXER_S16, 1, mx, &opt_pad, &elem); if (err < 0) @@ -912,7 +945,8 @@ int snd_scarlett_controls_create(struct usb_mixer_interface *mixer) for (i = 0; i < info->matrix_in; i++) { snprintf(mx, sizeof(mx), "Matrix %02d Input Playback Route", i+1); - err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum, 0x32, + err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum, + scarlett_ctl_enum_resume, 0x32, 0x06, i, USB_MIXER_S16, 1, mx, &info->opt_matrix, &elem); if (err < 0) @@ -921,7 +955,8 @@ int snd_scarlett_controls_create(struct usb_mixer_interface *mixer) for (o = 0; o < info->matrix_out; o++) { sprintf(mx, "Matrix %02d Mix %c Playback Volume", i+1, o+'A'); - err = add_new_ctl(mixer, &usb_scarlett_ctl, 0x3c, 0x00, + err = add_new_ctl(mixer, &usb_scarlett_ctl, + scarlett_ctl_resume, 0x3c, 0x00, (i << 3) + (o & 0x07), USB_MIXER_S16, 1, mx, NULL, &elem); if (err < 0) @@ -933,7 +968,8 @@ int snd_scarlett_controls_create(struct usb_mixer_interface *mixer) for (i = 0; i < info->input_len; i++) { snprintf(mx, sizeof(mx), "Input Source %02d Capture Route", i+1); - err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum, 0x34, + err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum, + scarlett_ctl_enum_resume, 0x34, 0x00, i, USB_MIXER_S16, 1, mx, &info->opt_master, &elem); if (err < 0) @@ -941,14 +977,15 @@ int snd_scarlett_controls_create(struct usb_mixer_interface *mixer) } /* val_len == 1 needed here */ - err = add_new_ctl(mixer, &usb_scarlett_ctl_enum, 0x28, 0x01, 0, + err = add_new_ctl(mixer, &usb_scarlett_ctl_enum, + scarlett_ctl_enum_resume, 0x28, 0x01, 0, USB_MIXER_U8, 1, "Sample Clock Source", &opt_clock, &elem); if (err < 0) return err; /* val_len == 1 and UAC2_CS_MEM */ - err = add_new_ctl(mixer, &usb_scarlett_ctl_sync, 0x3c, 0x00, 2, + err = add_new_ctl(mixer, &usb_scarlett_ctl_sync, NULL, 0x3c, 0x00, 2, USB_MIXER_U8, 1, "Sample Clock Sync Status", &opt_sync, &elem); if (err < 0) -- cgit v1.2.3 From d712eaf29d3fe5928d891a4a90ac58644ad595ed Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 21 Nov 2014 18:34:48 +0100 Subject: ALSA: core: Deletion of unnecessary checks before two function calls The functions snd_seq_oss_timer_delete() and vunmap() perform also input parameter validation. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Takashi Iwai --- sound/core/seq/oss/seq_oss_init.c | 9 +++------ sound/core/sgbuf.c | 3 +-- 2 files changed, 4 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c index b9184d20c39f..b0e32e161dd1 100644 --- a/sound/core/seq/oss/seq_oss_init.c +++ b/sound/core/seq/oss/seq_oss_init.c @@ -403,14 +403,11 @@ free_devinfo(void *private) { struct seq_oss_devinfo *dp = (struct seq_oss_devinfo *)private; - if (dp->timer) - snd_seq_oss_timer_delete(dp->timer); + snd_seq_oss_timer_delete(dp->timer); - if (dp->writeq) - snd_seq_oss_writeq_delete(dp->writeq); + snd_seq_oss_writeq_delete(dp->writeq); - if (dp->readq) - snd_seq_oss_readq_delete(dp->readq); + snd_seq_oss_readq_delete(dp->readq); kfree(dp); } diff --git a/sound/core/sgbuf.c b/sound/core/sgbuf.c index 0a418503ec41..84fffabdd129 100644 --- a/sound/core/sgbuf.c +++ b/sound/core/sgbuf.c @@ -39,8 +39,7 @@ int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab) if (! sgbuf) return -EINVAL; - if (dmab->area) - vunmap(dmab->area); + vunmap(dmab->area); dmab->area = NULL; tmpb.dev.type = SNDRV_DMA_TYPE_DEV; -- cgit v1.2.3 From 42d772101274492ca15258ea346e6ebbc2bc9bd0 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 21 Nov 2014 19:05:50 +0100 Subject: ALSA: es1688_lib: Deletion of an unnecessary check before the function call "release_and_free_resource" The release_and_free_resource() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Takashi Iwai --- sound/isa/es1688/es1688_lib.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c index de810e484bdf..b5450143407b 100644 --- a/sound/isa/es1688/es1688_lib.c +++ b/sound/isa/es1688/es1688_lib.c @@ -614,8 +614,7 @@ static int snd_es1688_free(struct snd_es1688 *chip) { if (chip->hardware != ES1688_HW_UNDEF) snd_es1688_init(chip, 0); - if (chip->res_port) - release_and_free_resource(chip->res_port); + release_and_free_resource(chip->res_port); if (chip->irq >= 0) free_irq(chip->irq, (void *) chip); if (chip->dma8 >= 0) { -- cgit v1.2.3 From 966b7bc9354ab8f59f0ef2d96306615157e0f76e Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 21 Nov 2014 19:32:02 +0100 Subject: ALSA: sb: Deletion of unnecessary checks before two function calls The functions release_and_free_resource() and snd_util_memhdr_free() test whether their argument is NULL and then return immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Takashi Iwai --- sound/isa/sb/emu8000_synth.c | 3 +-- sound/isa/sb/sb_common.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/isa/sb/emu8000_synth.c b/sound/isa/sb/emu8000_synth.c index 4e3fcfb15ad4..95b39beb61c1 100644 --- a/sound/isa/sb/emu8000_synth.c +++ b/sound/isa/sb/emu8000_synth.c @@ -105,8 +105,7 @@ static int snd_emu8000_delete_device(struct snd_seq_device *dev) snd_device_free(dev->card, hw->pcm); if (hw->emu) snd_emux_free(hw->emu); - if (hw->memhdr) - snd_util_memhdr_free(hw->memhdr); + snd_util_memhdr_free(hw->memhdr); hw->emu = NULL; hw->memhdr = NULL; return 0; diff --git a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c index 3ef990602cdd..f22b4480828e 100644 --- a/sound/isa/sb/sb_common.c +++ b/sound/isa/sb/sb_common.c @@ -184,8 +184,7 @@ static int snd_sbdsp_probe(struct snd_sb * chip) static int snd_sbdsp_free(struct snd_sb *chip) { - if (chip->res_port) - release_and_free_resource(chip->res_port); + release_and_free_resource(chip->res_port); if (chip->irq >= 0) free_irq(chip->irq, (void *) chip); #ifdef CONFIG_ISA -- cgit v1.2.3 From 4fc390a198c41a007c02f82f41ad100c7c67b55e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 22 Nov 2014 21:29:01 +0300 Subject: sound: oss: uart401: remove unneeded NULL check "devc" can't be NULL here so there is no need to check. Also I removed the "devc = NULL" assignment because devc is stored on stack so it's a no-op. Signed-off-by: Dan Carpenter Signed-off-by: Takashi Iwai --- sound/oss/uart401.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/oss/uart401.c b/sound/oss/uart401.c index 279bc565ac7e..dae4d4344407 100644 --- a/sound/oss/uart401.c +++ b/sound/oss/uart401.c @@ -412,13 +412,10 @@ void unload_uart401(struct address_info *hw_config) if (!devc->share_irq) free_irq(devc->irq, devc); - if (devc) - { - kfree(midi_devs[devc->my_dev]->converter); - kfree(midi_devs[devc->my_dev]); - kfree(devc); - devc = NULL; - } + kfree(midi_devs[devc->my_dev]->converter); + kfree(midi_devs[devc->my_dev]); + kfree(devc); + /* This kills midi_devs[x] */ sound_unload_mididev(hw_config->slots[4]); } -- cgit v1.2.3 From e9886ab06c1ef42451307c9367e344b2d8140e0b Mon Sep 17 00:00:00 2001 From: Eliot Blennerhassett Date: Thu, 20 Nov 2014 16:22:48 +1300 Subject: ALSA: asihpi: Minor string and dead code cleanup Signed-off-by: Eliot Blennerhassett Signed-off-by: Takashi Iwai --- sound/pci/asihpi/asihpi.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index ff9f9f1c0391..0e130dd8732e 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c @@ -28,7 +28,6 @@ #include "hpioctl.h" #include "hpicmn.h" - #include #include #include @@ -47,7 +46,7 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("AudioScience inc. "); -MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx " +MODULE_DESCRIPTION("AudioScience ALSA ASI5xxx ASI6xxx ASI87xx ASI89xx " HPI_VER_STRING); #if defined CONFIG_SND_DEBUG_VERBOSE @@ -87,11 +86,11 @@ MODULE_PARM_DESC(enable_hpi_hwdep, #ifdef KERNEL_ALSA_BUILD static char *build_info = "Built using headers from kernel source"; module_param(build_info, charp, S_IRUGO); -MODULE_PARM_DESC(build_info, "built using headers from kernel source"); +MODULE_PARM_DESC(build_info, "Built using headers from kernel source"); #else static char *build_info = "Built within ALSA source"; module_param(build_info, charp, S_IRUGO); -MODULE_PARM_DESC(build_info, "built within ALSA source"); +MODULE_PARM_DESC(build_info, "Built within ALSA source"); #endif /* set to 1 to dump every control from adapter to log */ @@ -538,7 +537,7 @@ static void snd_card_asihpi_pcm_timer_start(struct snd_pcm_substream * int expiry; expiry = HZ / 200; - /*? (dpcm->period_bytes * HZ / dpcm->bytes_per_sec); */ + expiry = max(expiry, 1); /* don't let it be zero! */ dpcm->timer.expires = jiffies + expiry; dpcm->respawn_timer = 1; @@ -2932,10 +2931,6 @@ static struct pci_driver driver = { .id_table = asihpi_pci_tbl, .probe = snd_asihpi_probe, .remove = snd_asihpi_remove, -#ifdef CONFIG_PM_SLEEP -/* .suspend = snd_asihpi_suspend, - .resume = snd_asihpi_resume, */ -#endif }; static int __init snd_asihpi_init(void) -- cgit v1.2.3 From 3872f19d96a55ec1d1e7af904d84457d91ef5a63 Mon Sep 17 00:00:00 2001 From: Eliot Blennerhassett Date: Thu, 20 Nov 2014 16:22:49 +1300 Subject: ALSA: asihpi: New I/O types - AVB & BLUlink, DAB Rf receiver Audio cards wth have AVB or BLU Link IO. Tuner card with DAB receiver Signed-off-by: Eliot Blennerhassett Signed-off-by: Takashi Iwai --- sound/pci/asihpi/asihpi.c | 25 ++++++++++++++++++------- sound/pci/asihpi/hpi.h | 16 ++++++++++++---- 2 files changed, 30 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index 0e130dd8732e..628ef7f146d9 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c @@ -109,7 +109,7 @@ static int adapter_fs = DEFAULT_SAMPLERATE; struct clk_source { int source; int index; - char *name; + const char *name; }; struct clk_cache { @@ -1292,8 +1292,9 @@ static const char * const asihpi_tuner_band_names[] = { "TV PAL I", "TV PAL DK", "TV SECAM", + "TV DAB", }; - +/* Number of strings must match the enumerations for HPI_TUNER_BAND in hpi.h */ compile_time_assert( (ARRAY_SIZE(asihpi_tuner_band_names) == (HPI_TUNER_BAND_LAST+1)), @@ -1313,9 +1314,11 @@ static const char * const asihpi_src_names[] = { "Analog", "Adapter", "RTP", - "Internal" + "Internal", + "AVB", + "BLU-Link" }; - +/* Number of strings must match the enumerations for HPI_SOURCENODES in hpi.h */ compile_time_assert( (ARRAY_SIZE(asihpi_src_names) == (HPI_SOURCENODE_LAST_INDEX-HPI_SOURCENODE_NONE+1)), @@ -1331,8 +1334,11 @@ static const char * const asihpi_dst_names[] = { "Net", "Analog", "RTP", + "AVB", + "Internal", + "BLU-Link" }; - +/* Number of strings must match the enumerations for HPI_DESTNODES in hpi.h */ compile_time_assert( (ARRAY_SIZE(asihpi_dst_names) == (HPI_DESTNODE_LAST_INDEX-HPI_DESTNODE_NONE+1)), @@ -2288,13 +2294,18 @@ static int snd_asihpi_cmode_add(struct snd_card_asihpi *asihpi, /*------------------------------------------------------------ Sampleclock source controls ------------------------------------------------------------*/ -static char *sampleclock_sources[MAX_CLOCKSOURCES] = { +static const char const *sampleclock_sources[] = { "N/A", "Local PLL", "Digital Sync", "Word External", "Word Header", "SMPTE", "Digital1", "Auto", "Network", "Invalid", - "Prev Module", + "Prev Module", "BLU-Link", "Digital2", "Digital3", "Digital4", "Digital5", "Digital6", "Digital7", "Digital8"}; + /* Number of strings must match expected enumerated values */ + compile_time_assert( + (ARRAY_SIZE(sampleclock_sources) == MAX_CLOCKSOURCES), + assert_sampleclock_sources_size); + static int snd_asihpi_clksrc_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { diff --git a/sound/pci/asihpi/hpi.h b/sound/pci/asihpi/hpi.h index 20887241a3ae..4466bd2c5272 100644 --- a/sound/pci/asihpi/hpi.h +++ b/sound/pci/asihpi/hpi.h @@ -196,8 +196,10 @@ enum HPI_SOURCENODES { packets of RTP audio samples from other devices. */ HPI_SOURCENODE_RTP_DESTINATION = 112, HPI_SOURCENODE_INTERNAL = 113, /**< node internal to the device. */ + HPI_SOURCENODE_AVB = 114, /**< AVB input stream */ + HPI_SOURCENODE_BLULINK = 115, /**< BLU-link input channel */ /* !!!Update this AND hpidebug.h if you add a new sourcenode type!!! */ - HPI_SOURCENODE_LAST_INDEX = 113 /**< largest ID */ + HPI_SOURCENODE_LAST_INDEX = 115 /**< largest ID */ /* AX6 max sourcenode types = 15 */ }; @@ -224,8 +226,11 @@ enum HPI_DESTNODES { /** RTP stream output node - This node is a source for packets of RTP audio samples that are sent to other devices. */ HPI_DESTNODE_RTP_SOURCE = 208, + HPI_DESTNODE_AVB = 209, /**< AVB output stream */ + HPI_DESTNODE_INTERNAL = 210, /**< node internal to the device. */ + HPI_DESTNODE_BLULINK = 211, /**< BLU-link output channel. */ /* !!!Update this AND hpidebug.h if you add a new destnode type!!! */ - HPI_DESTNODE_LAST_INDEX = 208 /**< largest ID */ + HPI_DESTNODE_LAST_INDEX = 211 /**< largest ID */ /* AX6 max destnode types = 15 */ }; @@ -752,7 +757,8 @@ enum HPI_TUNER_BAND { HPI_TUNER_BAND_TV_PAL_I = 7, /**< PAL-I TV band*/ HPI_TUNER_BAND_TV_PAL_DK = 8, /**< PAL-D/K TV band*/ HPI_TUNER_BAND_TV_SECAM_L = 9, /**< SECAM-L TV band*/ - HPI_TUNER_BAND_LAST = 9 /**< the index of the last tuner band. */ + HPI_TUNER_BAND_DAB = 10, + HPI_TUNER_BAND_LAST = 10 /**< the index of the last tuner band. */ }; /** Tuner mode attributes @@ -842,8 +848,10 @@ enum HPI_SAMPLECLOCK_SOURCES { HPI_SAMPLECLOCK_SOURCE_NETWORK = 8, /** From previous adjacent module (ASI2416 only)*/ HPI_SAMPLECLOCK_SOURCE_PREV_MODULE = 10, +/** Blu link sample clock*/ + HPI_SAMPLECLOCK_SOURCE_BLULINK = 11, /*! Update this if you add a new clock source.*/ - HPI_SAMPLECLOCK_SOURCE_LAST = 10 + HPI_SAMPLECLOCK_SOURCE_LAST = 11 }; /** Equalizer filter types. Used by HPI_ParametricEq_SetBand() -- cgit v1.2.3 From 35a8dc1f66a0fa88144fcbcd562eb2b2c1e36f11 Mon Sep 17 00:00:00 2001 From: Eliot Blennerhassett Date: Thu, 20 Nov 2014 16:22:50 +1300 Subject: ALSA: asihpi: Logging format improvements Signed-off-by: Eliot Blennerhassett Signed-off-by: Takashi Iwai --- sound/pci/asihpi/asihpi.c | 85 ++++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 46 deletions(-) (limited to 'sound') diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index 628ef7f146d9..c06903304e12 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c @@ -288,21 +288,17 @@ static void print_hwparams(struct snd_pcm_substream *substream, { char name[16]; snd_pcm_debug_name(substream, name, sizeof(name)); - snd_printd("%s HWPARAMS\n", name); - snd_printd(" samplerate %d Hz\n", params_rate(p)); - snd_printd(" channels %d\n", params_channels(p)); - snd_printd(" format %d\n", params_format(p)); - snd_printd(" subformat %d\n", params_subformat(p)); - snd_printd(" buffer %d B\n", params_buffer_bytes(p)); - snd_printd(" period %d B\n", params_period_bytes(p)); - snd_printd(" access %d\n", params_access(p)); - snd_printd(" period_size %d\n", params_period_size(p)); - snd_printd(" periods %d\n", params_periods(p)); - snd_printd(" buffer_size %d\n", params_buffer_size(p)); - snd_printd(" %d B/s\n", params_rate(p) * - params_channels(p) * + snd_printdd("%s HWPARAMS\n", name); + snd_printdd(" samplerate=%dHz channels=%d format=%d subformat=%d\n", + params_rate(p), params_channels(p), + params_format(p), params_subformat(p)); + snd_printdd(" buffer=%dB period=%dB period_size=%dB periods=%d\n", + params_buffer_bytes(p), params_period_bytes(p), + params_period_size(p), params_periods(p)); + snd_printdd(" buffer_size=%d access=%d data_rate=%dB/s\n", + params_buffer_size(p), params_access(p), + params_rate(p) * params_channels(p) * snd_pcm_format_width(params_format(p)) / 8); - } static snd_pcm_format_t hpi_to_alsa_formats[] = { @@ -480,7 +476,7 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream, params_buffer_bytes(params), runtime->dma_addr); if (err == 0) { snd_printdd( - "stream_host_buffer_attach succeeded %u %lu\n", + "stream_host_buffer_attach success %u %lu\n", params_buffer_bytes(params), (unsigned long)runtime->dma_addr); } else { @@ -490,12 +486,7 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream, } err = hpi_stream_get_info_ex(dpcm->h_stream, NULL, - &dpcm->hpi_buffer_attached, - NULL, NULL, NULL); - - snd_printdd("stream_host_buffer_attach status 0x%x\n", - dpcm->hpi_buffer_attached); - + &dpcm->hpi_buffer_attached, NULL, NULL, NULL); } bytes_per_sec = params_rate(params) * params_channels(params); width = snd_pcm_format_width(params_format(params)); @@ -563,10 +554,10 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, char name[16]; snd_pcm_debug_name(substream, name, sizeof(name)); - snd_printdd("%s trigger\n", name); switch (cmd) { case SNDRV_PCM_TRIGGER_START: + snd_printdd("%s trigger start\n", name); snd_pcm_group_for_each_entry(s, substream) { struct snd_pcm_runtime *runtime = s->runtime; struct snd_card_asihpi_pcm *ds = runtime->private_data; @@ -587,7 +578,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, * data?? */ unsigned int preload = ds->period_bytes * 1; - snd_printddd("%d preload x%x\n", s->number, preload); + snd_printddd("%d preload %d\n", s->number, preload); hpi_handle_error(hpi_outstream_write_buf( ds->h_stream, &runtime->dma_area[0], @@ -610,7 +601,6 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, } else break; } - snd_printdd("start\n"); /* start the master stream */ snd_card_asihpi_pcm_timer_start(substream); if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) || @@ -619,6 +609,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, break; case SNDRV_PCM_TRIGGER_STOP: + snd_printdd("%s trigger stop\n", name); snd_card_asihpi_pcm_timer_stop(substream); snd_pcm_group_for_each_entry(s, substream) { if (snd_pcm_substream_chip(s) != card) @@ -637,7 +628,6 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, } else break; } - snd_printdd("stop\n"); /* _prepare and _hwparams reset the stream */ hpi_handle_error(hpi_stream_stop(dpcm->h_stream)); @@ -650,12 +640,12 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - snd_printdd("pause release\n"); + snd_printdd("%s trigger pause release\n", name); hpi_handle_error(hpi_stream_start(dpcm->h_stream)); snd_card_asihpi_pcm_timer_start(substream); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - snd_printdd("pause\n"); + snd_printdd("%s trigger pause push\n", name); snd_card_asihpi_pcm_timer_stop(substream); hpi_handle_error(hpi_stream_stop(dpcm->h_stream)); break; @@ -730,7 +720,6 @@ static void snd_card_asihpi_timer_function(unsigned long data) snd_pcm_debug_name(substream, name, sizeof(name)); - snd_printdd("%s snd_card_asihpi_timer_function\n", name); /* find minimum newdata and buffer pos in group */ snd_pcm_group_for_each_entry(s, substream) { @@ -790,19 +779,20 @@ static void snd_card_asihpi_timer_function(unsigned long data) newdata); } - snd_printdd("hw_ptr 0x%04lX, appl_ptr 0x%04lX\n", + snd_printddd("timer1, %s, %d, S=%d, elap=%d, rw=%d, dsp=%d, left=%d, aux=%d, space=%d, hw_ptr=%ld, appl_ptr=%ld\n", + name, s->number, state, + ds->pcm_buf_elapsed_dma_ofs, + ds->pcm_buf_host_rw_ofs, + pcm_buf_dma_ofs, + (int)bytes_avail, + + (int)on_card_bytes, + buffer_size-bytes_avail, (unsigned long)frames_to_bytes(runtime, runtime->status->hw_ptr), (unsigned long)frames_to_bytes(runtime, - runtime->control->appl_ptr)); - - snd_printdd("%d S=%d, " - "rw=0x%04X, dma=0x%04X, left=0x%04X, " - "aux=0x%04X space=0x%04X\n", - s->number, state, - ds->pcm_buf_host_rw_ofs, pcm_buf_dma_ofs, - (int)bytes_avail, - (int)on_card_bytes, buffer_size-bytes_avail); + runtime->control->appl_ptr) + ); loops++; } pcm_buf_dma_ofs = min_buf_pos; @@ -820,7 +810,7 @@ static void snd_card_asihpi_timer_function(unsigned long data) next_jiffies = max(next_jiffies, 1U); dpcm->timer.expires = jiffies + next_jiffies; - snd_printdd("jif %d buf pos 0x%04X newdata 0x%04X xfer 0x%04X\n", + snd_printddd("timer2, jif=%d, buf_pos=%d, newdata=%d, xfer=%d\n", next_jiffies, pcm_buf_dma_ofs, newdata, xfercount); snd_pcm_group_for_each_entry(s, substream) { @@ -852,7 +842,7 @@ static void snd_card_asihpi_timer_function(unsigned long data) } if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) { - snd_printddd("P%d write1 0x%04X 0x%04X\n", + snd_printddd("write1, P=%d, xfer=%d, buf_ofs=%d\n", s->number, xfer1, buf_ofs); hpi_handle_error( hpi_outstream_write_buf( @@ -862,7 +852,7 @@ static void snd_card_asihpi_timer_function(unsigned long data) if (xfer2) { pd = s->runtime->dma_area; - snd_printddd("P%d write2 0x%04X 0x%04X\n", + snd_printddd("write2, P=%d, xfer=%d, buf_ofs=%d\n", s->number, xfercount - xfer1, buf_ofs); hpi_handle_error( @@ -872,7 +862,7 @@ static void snd_card_asihpi_timer_function(unsigned long data) &ds->format)); } } else { - snd_printddd("C%d read1 0x%04x\n", + snd_printddd("read1, C=%d, xfer=%d\n", s->number, xfer1); hpi_handle_error( hpi_instream_read_buf( @@ -880,7 +870,7 @@ static void snd_card_asihpi_timer_function(unsigned long data) pd, xfer1)); if (xfer2) { pd = s->runtime->dma_area; - snd_printddd("C%d read2 0x%04x\n", + snd_printddd("read2, C=%d, xfer=%d\n", s->number, xfer2); hpi_handle_error( hpi_instream_read_buf( @@ -933,7 +923,7 @@ snd_card_asihpi_playback_pointer(struct snd_pcm_substream *substream) snd_pcm_debug_name(substream, name, sizeof(name)); ptr = bytes_to_frames(runtime, dpcm->pcm_buf_dma_ofs % dpcm->buffer_bytes); - snd_printddd("%s pointer = 0x%04lx\n", name, (unsigned long)ptr); + snd_printddd("%s, pointer=%ld\n", name, (unsigned long)ptr); return ptr; } @@ -1081,9 +1071,10 @@ snd_card_asihpi_capture_pointer(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_card_asihpi_pcm *dpcm = runtime->private_data; + char name[16]; + snd_pcm_debug_name(substream, name, sizeof(name)); - snd_printddd("capture pointer %d=%d\n", - substream->number, dpcm->pcm_buf_dma_ofs); + snd_printddd("%s, pointer=%d\n", name, dpcm->pcm_buf_dma_ofs); /* NOTE Unlike playback can't use actual samples_played for the capture position, because those samples aren't yet in the local buffer available for reading. @@ -2867,6 +2858,8 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev, asihpi->in_min_chans = 1; } + snd_printk(KERN_INFO "update_interval_frames: %d", + asihpi->update_interval_frames); snd_printk(KERN_INFO "Has dma:%d, grouping:%d, mrx:%d\n", asihpi->can_dma, asihpi->support_grouping, -- cgit v1.2.3 From e51c58c982a0f81baa6fdee7331a8700c8586be5 Mon Sep 17 00:00:00 2001 From: Eliot Blennerhassett Date: Thu, 20 Nov 2014 16:22:51 +1300 Subject: ALSA: asihpi: Use CONFIG_64BIT directly Signed-off-by: Eliot Blennerhassett Signed-off-by: Takashi Iwai --- sound/pci/asihpi/hpi_internal.h | 16 ++++++++++------ sound/pci/asihpi/hpios.h | 4 ---- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/pci/asihpi/hpi_internal.h b/sound/pci/asihpi/hpi_internal.h index bc86cb726d79..c9bdc284cdaf 100644 --- a/sound/pci/asihpi/hpi_internal.h +++ b/sound/pci/asihpi/hpi_internal.h @@ -554,17 +554,21 @@ struct hpi_pci { struct pci_dev *pci_dev; }; +/** Adapter specification resource */ +struct hpi_adapter_specification { + u32 type; + u8 modules[4]; +}; + struct hpi_resource { union { const struct hpi_pci *pci; const char *net_if; + struct hpi_adapter_specification adapter_spec; + const void *sw_if; } r; -#ifndef HPI64BIT /* keep structure size constant */ - u32 pad_to64; -#endif u16 bus_type; /* HPI_BUS_PNPISA, _PCI, _USB etc */ u16 padding; - }; /** Format info used inside struct hpi_message @@ -582,7 +586,7 @@ struct hpi_msg_format { struct hpi_msg_data { struct hpi_msg_format format; u8 *pb_data; -#ifndef HPI64BIT +#ifndef CONFIG_64BIT u32 padding; #endif u32 data_size; @@ -595,7 +599,7 @@ struct hpi_data_legacy32 { u32 data_size; }; -#ifdef HPI64BIT +#ifdef CONFIG_64BIT /* Compatibility version of struct hpi_data*/ struct hpi_data_compat32 { struct hpi_msg_format format; diff --git a/sound/pci/asihpi/hpios.h b/sound/pci/asihpi/hpios.h index d3fbd0d76c37..d17d017940d8 100644 --- a/sound/pci/asihpi/hpios.h +++ b/sound/pci/asihpi/hpios.h @@ -41,10 +41,6 @@ HPI Operating System Specific macros for Linux Kernel driver #define HPI_NO_OS_FILE_OPS -#ifdef CONFIG_64BIT -#define HPI64BIT -#endif - /** Details of a memory area allocated with pci_alloc_consistent Need all info for parameters to pci_free_consistent */ -- cgit v1.2.3 From c1464a885444dd7e9c4491177ee102b64adc46c5 Mon Sep 17 00:00:00 2001 From: Eliot Blennerhassett Date: Thu, 20 Nov 2014 16:22:52 +1300 Subject: ALSA: asihpi: Refactor control cache code. Signed-off-by: Eliot Blennerhassett Signed-off-by: Takashi Iwai --- sound/pci/asihpi/hpicmn.c | 107 +++++++++++++++++++++++++++------------------- 1 file changed, 63 insertions(+), 44 deletions(-) (limited to 'sound') diff --git a/sound/pci/asihpi/hpicmn.c b/sound/pci/asihpi/hpicmn.c index 7ed5c26c3737..c7751243dc42 100644 --- a/sound/pci/asihpi/hpicmn.c +++ b/sound/pci/asihpi/hpicmn.c @@ -1,7 +1,7 @@ /****************************************************************************** AudioScience HPI driver - Copyright (C) 1997-2011 AudioScience Inc. + Copyright (C) 1997-2014 AudioScience Inc. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as @@ -206,6 +206,14 @@ static unsigned int control_cache_alloc_check(struct hpi_control_cache *pC) struct hpi_control_cache_info *info = (struct hpi_control_cache_info *) &p_master_cache[byte_count]; + u16 control_index = info->control_index; + + if (control_index >= pC->control_count) { + HPI_DEBUG_LOG(INFO, + "adap %d control index %d out of range, cache not ready?\n", + pC->adap_idx, control_index); + return 0; + } if (!info->size_in32bit_words) { if (!i) { @@ -225,10 +233,10 @@ static unsigned int control_cache_alloc_check(struct hpi_control_cache *pC) } if (info->control_type) { - pC->p_info[info->control_index] = info; + pC->p_info[control_index] = info; cached++; } else { /* dummy cache entry */ - pC->p_info[info->control_index] = NULL; + pC->p_info[control_index] = NULL; } byte_count += info->size_in32bit_words * 4; @@ -309,35 +317,18 @@ static const struct pad_ofs_size pad_desc[] = { /** CheckControlCache checks the cache and fills the struct hpi_response * accordingly. It returns one if a cache hit occurred, zero otherwise. */ -short hpi_check_control_cache(struct hpi_control_cache *p_cache, +short hpi_check_control_cache_single(struct hpi_control_cache_single *pC, struct hpi_message *phm, struct hpi_response *phr) { - short found = 1; - struct hpi_control_cache_info *pI; - struct hpi_control_cache_single *pC; size_t response_size; - if (!find_control(phm->obj_index, p_cache, &pI)) { - HPI_DEBUG_LOG(VERBOSE, - "HPICMN find_control() failed for adap %d\n", - phm->adapter_index); - return 0; - } - - phr->error = 0; - phr->specific_error = 0; - phr->version = 0; + short found = 1; /* set the default response size */ response_size = sizeof(struct hpi_response_header) + sizeof(struct hpi_control_res); - /* pC is the default cached control strucure. May be cast to - something else in the following switch statement. - */ - pC = (struct hpi_control_cache_single *)pI; - - switch (pI->control_type) { + switch (pC->u.i.control_type) { case HPI_CONTROL_METER: if (phm->u.c.attribute == HPI_METER_PEAK) { @@ -467,7 +458,7 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache, break; case HPI_CONTROL_PAD:{ struct hpi_control_cache_pad *p_pad; - p_pad = (struct hpi_control_cache_pad *)pI; + p_pad = (struct hpi_control_cache_pad *)pC; if (!(p_pad->field_valid_flags & (1 << HPI_CTL_ATTR_INDEX(phm->u.c. @@ -531,7 +522,8 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache, HPI_DEBUG_LOG(VERBOSE, "%s Adap %d, Ctl %d, Type %d, Attr %d\n", found ? "Cached" : "Uncached", phm->adapter_index, - pI->control_index, pI->control_type, phm->u.c.attribute); + pC->u.i.control_index, pC->u.i.control_type, + phm->u.c.attribute); if (found) { phr->size = (u16)response_size; @@ -543,34 +535,36 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache, return found; } -/** Updates the cache with Set values. - -Only update if no error. -Volume and Level return the limited values in the response, so use these -Multiplexer does so use sent values -*/ -void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *p_cache, +short hpi_check_control_cache(struct hpi_control_cache *p_cache, struct hpi_message *phm, struct hpi_response *phr) { - struct hpi_control_cache_single *pC; struct hpi_control_cache_info *pI; - if (phr->error) - return; - if (!find_control(phm->obj_index, p_cache, &pI)) { HPI_DEBUG_LOG(VERBOSE, "HPICMN find_control() failed for adap %d\n", phm->adapter_index); - return; + return 0; } - /* pC is the default cached control strucure. - May be cast to something else in the following switch statement. - */ - pC = (struct hpi_control_cache_single *)pI; + phr->error = 0; + phr->specific_error = 0; + phr->version = 0; + + return hpi_check_control_cache_single((struct hpi_control_cache_single + *)pI, phm, phr); +} + +/** Updates the cache with Set values. - switch (pI->control_type) { +Only update if no error. +Volume and Level return the limited values in the response, so use these +Multiplexer does so use sent values +*/ +void hpi_cmn_control_cache_sync_to_msg_single(struct hpi_control_cache_single + *pC, struct hpi_message *phm, struct hpi_response *phr) +{ + switch (pC->u.i.control_type) { case HPI_CONTROL_VOLUME: if (phm->u.c.attribute == HPI_VOLUME_GAIN) { pC->u.vol.an_log[0] = phr->u.c.an_log_value[0]; @@ -625,6 +619,30 @@ void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *p_cache, } } +void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *p_cache, + struct hpi_message *phm, struct hpi_response *phr) +{ + struct hpi_control_cache_single *pC; + struct hpi_control_cache_info *pI; + + if (phr->error) + return; + + if (!find_control(phm->obj_index, p_cache, &pI)) { + HPI_DEBUG_LOG(VERBOSE, + "HPICMN find_control() failed for adap %d\n", + phm->adapter_index); + return; + } + + /* pC is the default cached control strucure. + May be cast to something else in the following switch statement. + */ + pC = (struct hpi_control_cache_single *)pI; + + hpi_cmn_control_cache_sync_to_msg_single(pC, phm, phr); +} + /** Allocate control cache. \return Cache pointer, or NULL if allocation fails. @@ -637,12 +655,13 @@ struct hpi_control_cache *hpi_alloc_control_cache(const u32 control_count, if (!p_cache) return NULL; - p_cache->p_info = kcalloc(control_count, sizeof(*p_cache->p_info), - GFP_KERNEL); + p_cache->p_info = + kcalloc(control_count, sizeof(*p_cache->p_info), GFP_KERNEL); if (!p_cache->p_info) { kfree(p_cache); return NULL; } + p_cache->cache_size_in_bytes = size_in_bytes; p_cache->control_count = control_count; p_cache->p_cache = p_dsp_control_buffer; -- cgit v1.2.3 From f9a376c3f6d77e59d41350901b2bafbaf8791df0 Mon Sep 17 00:00:00 2001 From: Eliot Blennerhassett Date: Thu, 20 Nov 2014 16:22:53 +1300 Subject: ALSA: asihpi: Add support for stream interrupt. Some cards have a so-called low-latency mode, in which they present a single multichannel stream with no mixing or samplerate conversion. In this mode the card can generate an interrupt per internal processing block (typically 32 or 64 frames) Signed-off-by: Eliot Blennerhassett Signed-off-by: Takashi Iwai --- sound/pci/asihpi/asihpi.c | 177 +++++++++++++++++++++++++++++++++------- sound/pci/asihpi/hpi6205.c | 43 ++++++++-- sound/pci/asihpi/hpi_internal.h | 4 +- sound/pci/asihpi/hpicmn.h | 19 ++++- sound/pci/asihpi/hpioctl.c | 124 ++++++++++++++++++++++++++-- sound/pci/asihpi/hpios.h | 4 + 6 files changed, 321 insertions(+), 50 deletions(-) (limited to 'sound') diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index c06903304e12..ae29f30547cc 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c @@ -1,6 +1,6 @@ /* * Asihpi soundcard - * Copyright (c) by AudioScience Inc + * Copyright (c) by AudioScience Inc * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -124,6 +124,16 @@ struct snd_card_asihpi { struct pci_dev *pci; struct hpi_adapter *hpi; + /* In low latency mode there is only one stream, a pointer to its + * private data is stored here on trigger and cleared on stop. + * The interrupt handler uses it as a parameter when calling + * snd_card_asihpi_timer_function(). + */ + struct snd_card_asihpi_pcm *llmode_streampriv; + struct tasklet_struct t; + void (*pcm_start)(struct snd_pcm_substream *substream); + void (*pcm_stop)(struct snd_pcm_substream *substream); + u32 h_mixer; struct clk_cache cc; @@ -544,6 +554,48 @@ static void snd_card_asihpi_pcm_timer_stop(struct snd_pcm_substream *substream) del_timer(&dpcm->timer); } +static void snd_card_asihpi_pcm_int_start(struct snd_pcm_substream *substream) +{ + struct snd_card_asihpi_pcm *dpcm; + struct snd_card_asihpi *card; + + BUG_ON(!substream); + + dpcm = (struct snd_card_asihpi_pcm *)substream->runtime->private_data; + card = snd_pcm_substream_chip(substream); + + BUG_ON(in_interrupt()); + tasklet_disable(&card->t); + card->llmode_streampriv = dpcm; + tasklet_enable(&card->t); + + hpi_handle_error(hpi_adapter_set_property(card->hpi->adapter->index, + HPI_ADAPTER_PROPERTY_IRQ_RATE, + card->update_interval_frames, 0)); +} + +static void snd_card_asihpi_pcm_int_stop(struct snd_pcm_substream *substream) +{ + struct snd_card_asihpi_pcm *dpcm; + struct snd_card_asihpi *card; + + BUG_ON(!substream); + + dpcm = (struct snd_card_asihpi_pcm *)substream->runtime->private_data; + card = snd_pcm_substream_chip(substream); + + hpi_handle_error(hpi_adapter_set_property(card->hpi->adapter->index, + HPI_ADAPTER_PROPERTY_IRQ_RATE, 0, 0)); + + if (in_interrupt()) + card->llmode_streampriv = NULL; + else { + tasklet_disable(&card->t); + card->llmode_streampriv = NULL; + tasklet_enable(&card->t); + } +} + static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, int cmd) { @@ -602,7 +654,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, break; } /* start the master stream */ - snd_card_asihpi_pcm_timer_start(substream); + card->pcm_start(substream); if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) || !card->can_dma) hpi_handle_error(hpi_stream_start(dpcm->h_stream)); @@ -610,7 +662,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_STOP: snd_printdd("%s trigger stop\n", name); - snd_card_asihpi_pcm_timer_stop(substream); + card->pcm_stop(substream); snd_pcm_group_for_each_entry(s, substream) { if (snd_pcm_substream_chip(s) != card) continue; @@ -641,12 +693,12 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: snd_printdd("%s trigger pause release\n", name); + card->pcm_start(substream); hpi_handle_error(hpi_stream_start(dpcm->h_stream)); - snd_card_asihpi_pcm_timer_start(substream); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: snd_printdd("%s trigger pause push\n", name); - snd_card_asihpi_pcm_timer_stop(substream); + card->pcm_stop(substream); hpi_handle_error(hpi_stream_stop(dpcm->h_stream)); break; default: @@ -718,8 +770,8 @@ static void snd_card_asihpi_timer_function(unsigned long data) u32 buffer_size, bytes_avail, samples_played, on_card_bytes; char name[16]; - snd_pcm_debug_name(substream, name, sizeof(name)); + snd_pcm_debug_name(substream, name, sizeof(name)); /* find minimum newdata and buffer pos in group */ snd_pcm_group_for_each_entry(s, substream) { @@ -779,7 +831,8 @@ static void snd_card_asihpi_timer_function(unsigned long data) newdata); } - snd_printddd("timer1, %s, %d, S=%d, elap=%d, rw=%d, dsp=%d, left=%d, aux=%d, space=%d, hw_ptr=%ld, appl_ptr=%ld\n", + snd_printddd( + "timer1, %s, %d, S=%d, elap=%d, rw=%d, dsp=%d, left=%d, aux=%d, space=%d, hw_ptr=%ld, appl_ptr=%ld\n", name, s->number, state, ds->pcm_buf_elapsed_dma_ofs, ds->pcm_buf_host_rw_ofs, @@ -815,11 +868,13 @@ static void snd_card_asihpi_timer_function(unsigned long data) snd_pcm_group_for_each_entry(s, substream) { struct snd_card_asihpi_pcm *ds = s->runtime->private_data; + runtime = s->runtime; /* don't link Cap and Play */ if (substream->stream != s->stream) continue; + /* Store dma offset for use by pointer callback */ ds->pcm_buf_dma_ofs = pcm_buf_dma_ofs; if (xfercount && @@ -878,16 +933,38 @@ static void snd_card_asihpi_timer_function(unsigned long data) pd, xfer2)); } } + /* ? host_rw_ofs always ahead of elapsed_dma_ofs by preload size? */ ds->pcm_buf_host_rw_ofs += xfercount; ds->pcm_buf_elapsed_dma_ofs += xfercount; snd_pcm_period_elapsed(s); } } - if (dpcm->respawn_timer) + if (!card->hpi->interrupt_mode && dpcm->respawn_timer) add_timer(&dpcm->timer); } +static void snd_card_asihpi_int_task(unsigned long data) +{ + struct hpi_adapter *a = (struct hpi_adapter *)data; + struct snd_card_asihpi *asihpi; + + WARN_ON(!a || !a->snd_card || !a->snd_card->private_data); + asihpi = (struct snd_card_asihpi *)a->snd_card->private_data; + if (asihpi->llmode_streampriv) + snd_card_asihpi_timer_function( + (unsigned long)asihpi->llmode_streampriv); +} + +static void snd_card_asihpi_isr(struct hpi_adapter *a) +{ + struct snd_card_asihpi *asihpi; + + WARN_ON(!a || !a->snd_card || !a->snd_card->private_data); + asihpi = (struct snd_card_asihpi *)a->snd_card->private_data; + tasklet_schedule(&asihpi->t); +} + /***************************** PLAYBACK OPS ****************/ static int snd_card_asihpi_playback_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg) @@ -995,13 +1072,22 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream) runtime->private_free = snd_card_asihpi_runtime_free; memset(&snd_card_asihpi_playback, 0, sizeof(snd_card_asihpi_playback)); - snd_card_asihpi_playback.buffer_bytes_max = BUFFER_BYTES_MAX; - snd_card_asihpi_playback.period_bytes_min = PERIOD_BYTES_MIN; - /*?snd_card_asihpi_playback.period_bytes_min = - card->out_max_chans * 4096; */ - snd_card_asihpi_playback.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN; - snd_card_asihpi_playback.periods_min = PERIODS_MIN; - snd_card_asihpi_playback.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN; + if (!card->hpi->interrupt_mode) { + snd_card_asihpi_playback.buffer_bytes_max = BUFFER_BYTES_MAX; + snd_card_asihpi_playback.period_bytes_min = PERIOD_BYTES_MIN; + snd_card_asihpi_playback.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN; + snd_card_asihpi_playback.periods_min = PERIODS_MIN; + snd_card_asihpi_playback.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN; + } else { + size_t pbmin = card->update_interval_frames * + card->out_max_chans; + snd_card_asihpi_playback.buffer_bytes_max = BUFFER_BYTES_MAX; + snd_card_asihpi_playback.period_bytes_min = pbmin; + snd_card_asihpi_playback.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN; + snd_card_asihpi_playback.periods_min = PERIODS_MIN; + snd_card_asihpi_playback.periods_max = BUFFER_BYTES_MAX / pbmin; + } + /* snd_card_asihpi_playback.fifo_size = 0; */ snd_card_asihpi_playback.channels_max = card->out_max_chans; snd_card_asihpi_playback.channels_min = card->out_min_chans; @@ -1036,7 +1122,7 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream) card->update_interval_frames); snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, - card->update_interval_frames * 2, UINT_MAX); + card->update_interval_frames, UINT_MAX); snd_printdd("playback open\n"); @@ -1102,8 +1188,6 @@ static int snd_card_asihpi_capture_prepare(struct snd_pcm_substream *substream) return 0; } - - static u64 snd_card_asihpi_capture_formats(struct snd_card_asihpi *asihpi, u32 h_stream) { @@ -1170,11 +1254,21 @@ static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream) runtime->private_free = snd_card_asihpi_runtime_free; memset(&snd_card_asihpi_capture, 0, sizeof(snd_card_asihpi_capture)); - snd_card_asihpi_capture.buffer_bytes_max = BUFFER_BYTES_MAX; - snd_card_asihpi_capture.period_bytes_min = PERIOD_BYTES_MIN; - snd_card_asihpi_capture.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN; - snd_card_asihpi_capture.periods_min = PERIODS_MIN; - snd_card_asihpi_capture.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN; + if (!card->hpi->interrupt_mode) { + snd_card_asihpi_capture.buffer_bytes_max = BUFFER_BYTES_MAX; + snd_card_asihpi_capture.period_bytes_min = PERIOD_BYTES_MIN; + snd_card_asihpi_capture.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN; + snd_card_asihpi_capture.periods_min = PERIODS_MIN; + snd_card_asihpi_capture.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN; + } else { + size_t pbmin = card->update_interval_frames * + card->out_max_chans; + snd_card_asihpi_capture.buffer_bytes_max = BUFFER_BYTES_MAX; + snd_card_asihpi_capture.period_bytes_min = pbmin; + snd_card_asihpi_capture.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN; + snd_card_asihpi_capture.periods_min = PERIODS_MIN; + snd_card_asihpi_capture.periods_max = BUFFER_BYTES_MAX / pbmin; + } /* snd_card_asihpi_capture.fifo_size = 0; */ snd_card_asihpi_capture.channels_max = card->in_max_chans; snd_card_asihpi_capture.channels_min = card->in_min_chans; @@ -1199,7 +1293,7 @@ static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream) snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, card->update_interval_frames); snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, - card->update_interval_frames * 2, UINT_MAX); + card->update_interval_frames, UINT_MAX); snd_pcm_set_sync(substream); @@ -2444,15 +2538,19 @@ static int snd_asihpi_clkrate_get(struct snd_kcontrol *kcontrol, static int snd_asihpi_sampleclock_add(struct snd_card_asihpi *asihpi, struct hpi_control *hpi_ctl) { - struct snd_card *card = asihpi->card; + struct snd_card *card; struct snd_kcontrol_new snd_control; - struct clk_cache *clkcache = &asihpi->cc; + struct clk_cache *clkcache; u32 hSC = hpi_ctl->h_control; int has_aes_in = 0; int i, j; u16 source; + if (snd_BUG_ON(!asihpi)) + return -EINVAL; + card = asihpi->card; + clkcache = &asihpi->cc; snd_control.private_value = hpi_ctl->h_control; clkcache->has_local = 0; @@ -2808,6 +2906,7 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev, asihpi->card = card; asihpi->pci = pci_dev; asihpi->hpi = hpi; + hpi->snd_card = card; snd_printk(KERN_INFO "adapter ID=%4X index=%d\n", asihpi->hpi->adapter->type, adapter_index); @@ -2830,8 +2929,16 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev, if (err) asihpi->update_interval_frames = 512; - if (!asihpi->can_dma) - asihpi->update_interval_frames *= 2; + if (hpi->interrupt_mode) { + asihpi->pcm_start = snd_card_asihpi_pcm_int_start; + asihpi->pcm_stop = snd_card_asihpi_pcm_int_stop; + tasklet_init(&asihpi->t, snd_card_asihpi_int_task, + (unsigned long)hpi); + hpi->interrupt_callback = snd_card_asihpi_isr; + } else { + asihpi->pcm_start = snd_card_asihpi_pcm_timer_start; + asihpi->pcm_stop = snd_card_asihpi_pcm_timer_stop; + } hpi_handle_error(hpi_instream_open(adapter_index, 0, &h_stream)); @@ -2841,6 +2948,9 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev, hpi_handle_error(hpi_instream_close(h_stream)); + if (!asihpi->can_dma) + asihpi->update_interval_frames *= 2; + err = hpi_adapter_get_property(adapter_index, HPI_ADAPTER_PROPERTY_CURCHANNELS, &asihpi->in_max_chans, &asihpi->out_max_chans); @@ -2900,7 +3010,6 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev, err = snd_card_register(card); if (!err) { - hpi->snd_card = card; dev++; return 0; } @@ -2914,6 +3023,16 @@ __nodev: static void snd_asihpi_remove(struct pci_dev *pci_dev) { struct hpi_adapter *hpi = pci_get_drvdata(pci_dev); + struct snd_card_asihpi *asihpi = hpi->snd_card->private_data; + + /* Stop interrupts */ + if (hpi->interrupt_mode) { + hpi->interrupt_callback = NULL; + hpi_handle_error(hpi_adapter_set_property(hpi->adapter->index, + HPI_ADAPTER_PROPERTY_IRQ_RATE, 0, 0)); + tasklet_kill(&asihpi->t); + } + snd_card_free(hpi->snd_card); hpi->snd_card = NULL; asihpi_adapter_remove(pci_dev); diff --git a/sound/pci/asihpi/hpi6205.c b/sound/pci/asihpi/hpi6205.c index 4f2873880b16..8d5abfa4e24b 100644 --- a/sound/pci/asihpi/hpi6205.c +++ b/sound/pci/asihpi/hpi6205.c @@ -1,7 +1,7 @@ /****************************************************************************** AudioScience HPI driver - Copyright (C) 1997-2011 AudioScience Inc. + Copyright (C) 1997-2014 AudioScience Inc. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as @@ -163,6 +163,9 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao, static void delete_adapter_obj(struct hpi_adapter_obj *pao); +static int adapter_irq_query_and_clear(struct hpi_adapter_obj *pao, + u32 message); + static void outstream_host_buffer_allocate(struct hpi_adapter_obj *pao, struct hpi_message *phm, struct hpi_response *phr); @@ -283,7 +286,6 @@ static void adapter_message(struct hpi_adapter_obj *pao, case HPI_ADAPTER_DELETE: adapter_delete(pao, phm, phr); break; - default: hw_message(pao, phm, phr); break; @@ -673,6 +675,12 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao, HPI_DEBUG_LOG(INFO, "bootload DSP OK\n"); + pao->irq_query_and_clear = adapter_irq_query_and_clear; + pao->instream_host_buffer_status = + phw->p_interface_buffer->instream_host_buffer_status; + pao->outstream_host_buffer_status = + phw->p_interface_buffer->outstream_host_buffer_status; + return hpi_add_adapter(pao); } @@ -713,6 +721,21 @@ static void delete_adapter_obj(struct hpi_adapter_obj *pao) /*****************************************************************************/ /* Adapter functions */ +static int adapter_irq_query_and_clear(struct hpi_adapter_obj *pao, + u32 message) +{ + struct hpi_hw_obj *phw = pao->priv; + u32 hsr = 0; + + hsr = ioread32(phw->prHSR); + if (hsr & C6205_HSR_INTSRC) { + /* reset the interrupt from the DSP */ + iowrite32(C6205_HSR_INTSRC, phw->prHSR); + return HPI_IRQ_MIXER; + } + + return HPI_IRQ_NONE; +} /*****************************************************************************/ /* OutStream Host buffer functions */ @@ -1331,17 +1354,21 @@ static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao, if (boot_code_id[1] != 0) { /* DSP 1 is a C6713 */ /* CLKX0 <- '1' release the C6205 bootmode pulldowns */ - boot_loader_write_mem32(pao, 0, (0x018C0024L), 0x00002202); + boot_loader_write_mem32(pao, 0, 0x018C0024, 0x00002202); hpios_delay_micro_seconds(100); /* Reset the 6713 #1 - revB */ boot_loader_write_mem32(pao, 0, C6205_BAR0_TIMER1_CTL, 0); - - /* dummy read every 4 words for 6205 advisory 1.4.4 */ - boot_loader_read_mem32(pao, 0, 0); - + /* value of bit 3 is unknown after DSP reset, other bits shoudl be 0 */ + if (0 != (boot_loader_read_mem32(pao, 0, + (C6205_BAR0_TIMER1_CTL)) & ~8)) + return HPI6205_ERROR_6205_REG; hpios_delay_micro_seconds(100); + /* Release C6713 from reset - revB */ boot_loader_write_mem32(pao, 0, C6205_BAR0_TIMER1_CTL, 4); + if (4 != (boot_loader_read_mem32(pao, 0, + (C6205_BAR0_TIMER1_CTL)) & ~8)) + return HPI6205_ERROR_6205_REG; hpios_delay_micro_seconds(100); } @@ -2089,7 +2116,7 @@ static u16 message_response_sequence(struct hpi_adapter_obj *pao, return 0; } - /* Assume buffer of type struct bus_master_interface + /* Assume buffer of type struct bus_master_interface_62 is allocated "noncacheable" */ if (!wait_dsp_ack(phw, H620_HIF_IDLE, HPI6205_TIMEOUT)) { diff --git a/sound/pci/asihpi/hpi_internal.h b/sound/pci/asihpi/hpi_internal.h index c9bdc284cdaf..48380ce2c81b 100644 --- a/sound/pci/asihpi/hpi_internal.h +++ b/sound/pci/asihpi/hpi_internal.h @@ -686,8 +686,8 @@ union hpi_adapterx_msg { u16 value; } test_assert; struct { - u32 yes; - } irq_query; + u32 message; + } irq; u32 pad[3]; }; diff --git a/sound/pci/asihpi/hpicmn.h b/sound/pci/asihpi/hpicmn.h index e44121283047..46629c2d101b 100644 --- a/sound/pci/asihpi/hpicmn.h +++ b/sound/pci/asihpi/hpicmn.h @@ -1,7 +1,7 @@ /** AudioScience HPI driver - Copyright (C) 1997-2011 AudioScience Inc. + Copyright (C) 1997-2014 AudioScience Inc. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as @@ -21,7 +21,11 @@ struct hpi_adapter_obj; /* a function that takes an adapter obj and returns an int */ -typedef int adapter_int_func(struct hpi_adapter_obj *pao); +typedef int adapter_int_func(struct hpi_adapter_obj *pao, u32 message); + +#define HPI_IRQ_NONE (0) +#define HPI_IRQ_MESSAGE (1) +#define HPI_IRQ_MIXER (2) struct hpi_adapter_obj { struct hpi_pci pci; /* PCI info - bus#,dev#,address etc */ @@ -33,6 +37,9 @@ struct hpi_adapter_obj { u16 dsp_crashed; u16 has_control_cache; void *priv; + adapter_int_func *irq_query_and_clear; + struct hpi_hostbuffer_status *instream_host_buffer_status; + struct hpi_hostbuffer_status *outstream_host_buffer_status; }; struct hpi_control_cache { @@ -55,13 +62,21 @@ void hpi_delete_adapter(struct hpi_adapter_obj *pao); short hpi_check_control_cache(struct hpi_control_cache *pC, struct hpi_message *phm, struct hpi_response *phr); + +short hpi_check_control_cache_single(struct hpi_control_cache_single *pC, + struct hpi_message *phm, struct hpi_response *phr); + struct hpi_control_cache *hpi_alloc_control_cache(const u32 number_of_controls, const u32 size_in_bytes, u8 *pDSP_control_buffer); + void hpi_free_control_cache(struct hpi_control_cache *p_cache); void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *pC, struct hpi_message *phm, struct hpi_response *phr); +void hpi_cmn_control_cache_sync_to_msg_single(struct hpi_control_cache_single + *pC, struct hpi_message *phm, struct hpi_response *phr); + u16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr); hpi_handler_func HPI_COMMON; diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c index 7f0272032fbb..9454932fc9c0 100644 --- a/sound/pci/asihpi/hpioctl.c +++ b/sound/pci/asihpi/hpioctl.c @@ -1,7 +1,8 @@ /******************************************************************************* - AudioScience HPI driver - Copyright (C) 1997-2011 AudioScience Inc. + Common Linux HPI ioctl and module probe/remove functions + + Copyright (C) 1997-2014 AudioScience Inc. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as @@ -12,11 +13,6 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -Common Linux HPI ioctl and module probe/remove functions *******************************************************************************/ #define SOURCEFILE_NAME "hpioctl.c" @@ -29,6 +25,7 @@ Common Linux HPI ioctl and module probe/remove functions #include "hpicmn.h" #include +#include #include #include #include @@ -307,10 +304,38 @@ out: return err; } +static int asihpi_irq_count; + +static irqreturn_t asihpi_isr(int irq, void *dev_id) +{ + struct hpi_adapter *a = dev_id; + int handled; + + if (!a->adapter->irq_query_and_clear) { + pr_err("asihpi_isr ASI%04X:%d no handler\n", a->adapter->type, + a->adapter->index); + return IRQ_NONE; + } + + handled = a->adapter->irq_query_and_clear(a->adapter, 0); + + if (!handled) + return IRQ_NONE; + + asihpi_irq_count++; + /* printk(KERN_INFO "asihpi_isr %d ASI%04X:%d irq handled\n", + asihpi_irq_count, a->adapter->type, a->adapter->index); */ + + if (a->interrupt_callback) + a->interrupt_callback(a); + + return IRQ_HANDLED; +} + int asihpi_adapter_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { - int idx, nm; + int idx, nm, low_latency_mode = 0, irq_supported = 0; int adapter_index; unsigned int memlen; struct hpi_message hm; @@ -388,8 +413,39 @@ int asihpi_adapter_probe(struct pci_dev *pci_dev, hm.adapter_index = adapter.adapter->index; hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); - if (hr.error) + if (hr.error) { + HPI_DEBUG_LOG(ERROR, "HPI_ADAPTER_OPEN failed, aborting\n"); + goto err; + } + + /* Check if current mode == Low Latency mode */ + hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, + HPI_ADAPTER_GET_MODE); + hm.adapter_index = adapter.adapter->index; + hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); + + if (hr.error) { + HPI_DEBUG_LOG(ERROR, + "HPI_ADAPTER_GET_MODE failed, aborting\n"); goto err; + } + + if (hr.u.ax.mode.adapter_mode == HPI_ADAPTER_MODE_LOW_LATENCY) + low_latency_mode = 1; + + /* Check if IRQs are supported */ + hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, + HPI_ADAPTER_GET_PROPERTY); + hm.adapter_index = adapter.adapter->index; + hm.u.ax.property_set.property = HPI_ADAPTER_PROPERTY_SUPPORTS_IRQ; + hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); + if (hr.error || !hr.u.ax.property_get.parameter1) { + dev_info(&pci_dev->dev, + "IRQs not supported by adapter at index %d\n", + adapter.adapter->index); + } else { + irq_supported = 1; + } /* WARNING can't init mutex in 'adapter' * and then copy it to adapters[] ?!?! @@ -398,6 +454,44 @@ int asihpi_adapter_probe(struct pci_dev *pci_dev, mutex_init(&adapters[adapter_index].mutex); pci_set_drvdata(pci_dev, &adapters[adapter_index]); + if (low_latency_mode && irq_supported) { + if (!adapter.adapter->irq_query_and_clear) { + dev_err(&pci_dev->dev, + "no IRQ handler for adapter %d, aborting\n", + adapter.adapter->index); + goto err; + } + + /* Disable IRQ generation on DSP side by setting the rate to 0 */ + hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, + HPI_ADAPTER_SET_PROPERTY); + hm.adapter_index = adapter.adapter->index; + hm.u.ax.property_set.property = HPI_ADAPTER_PROPERTY_IRQ_RATE; + hm.u.ax.property_set.parameter1 = 0; + hm.u.ax.property_set.parameter2 = 0; + hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); + if (hr.error) { + HPI_DEBUG_LOG(ERROR, + "HPI_ADAPTER_GET_MODE failed, aborting\n"); + goto err; + } + + /* Note: request_irq calls asihpi_isr here */ + if (request_irq(pci_dev->irq, asihpi_isr, IRQF_SHARED, + "asihpi", &adapters[adapter_index])) { + dev_err(&pci_dev->dev, "request_irq(%d) failed\n", + pci_dev->irq); + goto err; + } + + adapters[adapter_index].interrupt_mode = 1; + + dev_info(&pci_dev->dev, "using irq %d\n", pci_dev->irq); + adapters[adapter_index].irq = pci_dev->irq; + } else { + dev_info(&pci_dev->dev, "using polled mode\n"); + } + dev_info(&pci_dev->dev, "probe succeeded for ASI%04X HPI index %d\n", adapter.adapter->type, adapter_index); @@ -431,6 +525,15 @@ void asihpi_adapter_remove(struct pci_dev *pci_dev) pa = pci_get_drvdata(pci_dev); pci = pa->adapter->pci; + /* Disable IRQ generation on DSP side */ + hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, + HPI_ADAPTER_SET_PROPERTY); + hm.adapter_index = pa->adapter->index; + hm.u.ax.property_set.property = HPI_ADAPTER_PROPERTY_IRQ_RATE; + hm.u.ax.property_set.parameter1 = 0; + hm.u.ax.property_set.parameter2 = 0; + hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); + hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, HPI_ADAPTER_DELETE); hm.adapter_index = pa->adapter->index; @@ -442,6 +545,9 @@ void asihpi_adapter_remove(struct pci_dev *pci_dev) iounmap(pci.ap_mem_base[idx]); } + if (pa->irq) + free_irq(pa->irq, pa); + if (pa->p_buffer) vfree(pa->p_buffer); diff --git a/sound/pci/asihpi/hpios.h b/sound/pci/asihpi/hpios.h index d17d017940d8..4e383601b9cf 100644 --- a/sound/pci/asihpi/hpios.h +++ b/sound/pci/asihpi/hpios.h @@ -151,6 +151,10 @@ struct hpi_adapter { struct hpi_adapter_obj *adapter; struct snd_card *snd_card; + int irq; + int interrupt_mode; + void (*interrupt_callback) (struct hpi_adapter *); + /* mutex prevents contention for one card between multiple user programs (via ioctl) */ struct mutex mutex; -- cgit v1.2.3 From 5bc91f5b3c732bdb3b9e7cc8bd27969d25015bcd Mon Sep 17 00:00:00 2001 From: Eliot Blennerhassett Date: Thu, 20 Nov 2014 16:22:54 +1300 Subject: ALSA: asihpi: Turn off msg/resp logging after DSP has crashed. Prevents spewing of useless messages if app keeps trying to access the card. Signed-off-by: Eliot Blennerhassett Signed-off-by: Takashi Iwai --- sound/pci/asihpi/hpimsgx.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/pci/asihpi/hpimsgx.c b/sound/pci/asihpi/hpimsgx.c index d4790ddc225c..736f45337fc7 100644 --- a/sound/pci/asihpi/hpimsgx.c +++ b/sound/pci/asihpi/hpimsgx.c @@ -1,7 +1,7 @@ /****************************************************************************** AudioScience HPI driver - Copyright (C) 1997-2011 AudioScience Inc. + Copyright (C) 1997-2014 AudioScience Inc. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as @@ -35,6 +35,7 @@ static struct pci_device_id asihpi_pci_tbl[] = { static struct hpios_spinlock msgx_lock; static hpi_handler_func *hpi_entry_points[HPI_MAX_ADAPTERS]; +static int logging_enabled = 1; static hpi_handler_func *hpi_lookup_entry_point_function(const struct hpi_pci *pci_info) @@ -312,7 +313,9 @@ static void instream_message(struct hpi_message *phm, void hpi_send_recv_ex(struct hpi_message *phm, struct hpi_response *phr, void *h_owner) { - HPI_DEBUG_MESSAGE(DEBUG, phm); + + if (logging_enabled) + HPI_DEBUG_MESSAGE(DEBUG, phm); if (phm->type != HPI_TYPE_REQUEST) { hpi_init_response(phr, phm->object, phm->function, @@ -352,8 +355,14 @@ void hpi_send_recv_ex(struct hpi_message *phm, struct hpi_response *phr, hw_entry_point(phm, phr); break; } - HPI_DEBUG_RESPONSE(phr); + if (logging_enabled) + HPI_DEBUG_RESPONSE(phr); + + if (phr->error >= HPI_ERROR_DSP_COMMUNICATION) { + hpi_debug_level_set(HPI_DEBUG_LEVEL_ERROR); + logging_enabled = 0; + } } static void adapter_open(struct hpi_message *phm, struct hpi_response *phr) -- cgit v1.2.3 From 12eb0898741870882ca474708e811983d5a5d768 Mon Sep 17 00:00:00 2001 From: Eliot Blennerhassett Date: Thu, 20 Nov 2014 16:22:55 +1300 Subject: ALSA: asihpi: Use standard printk helpers Signed-off-by: Eliot Blennerhassett Signed-off-by: Takashi Iwai --- sound/pci/asihpi/asihpi.c | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) (limited to 'sound') diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index ae29f30547cc..e9273fb2a505 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c @@ -380,7 +380,7 @@ static void snd_card_asihpi_pcm_samplerates(struct snd_card_asihpi *asihpi, HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0, HPI_CONTROL_SAMPLECLOCK, &h_control); if (err) { - snd_printk(KERN_ERR + dev_err(&asihpi->pci->dev, "No local sampleclock, err %d\n", err); } @@ -1438,7 +1438,7 @@ static inline int ctl_add(struct snd_card *card, struct snd_kcontrol_new *ctl, if (err < 0) return err; else if (mixer_dump) - snd_printk(KERN_INFO "added %s(%d)\n", ctl->name, ctl->index); + dev_info(&asihpi->pci->dev, "added %s(%d)\n", ctl->name, ctl->index); return 0; } @@ -2652,7 +2652,7 @@ static int snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi) if (err) { if (err == HPI_ERROR_CONTROL_DISABLED) { if (mixer_dump) - snd_printk(KERN_INFO + dev_info(&asihpi->pci->dev, "Disabled HPI Control(%d)\n", idx); continue; @@ -2717,9 +2717,8 @@ static int snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi) case HPI_CONTROL_COMPANDER: default: if (mixer_dump) - snd_printk(KERN_INFO - "Untranslated HPI Control" - "(%d) %d %d %d %d %d\n", + dev_info(&asihpi->pci->dev, + "Untranslated HPI Control (%d) %d %d %d %d %d\n", idx, hpi_ctl.control_type, hpi_ctl.src_node_type, @@ -2734,7 +2733,7 @@ static int snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi) if (HPI_ERROR_INVALID_OBJ_INDEX != err) hpi_handle_error(err); - snd_printk(KERN_INFO "%d mixer controls found\n", idx); + dev_info(&asihpi->pci->dev, "%d mixer controls found\n", idx); return 0; } @@ -2897,8 +2896,7 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev, &card); if (err < 0) return err; - snd_printk(KERN_WARNING - "**** WARNING **** Adapter index %d->ALSA index %d\n", + dev_warn(&pci_dev->dev, "Adapter index %d->ALSA index %d\n", adapter_index, card->number); } @@ -2908,9 +2906,6 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev, asihpi->hpi = hpi; hpi->snd_card = card; - snd_printk(KERN_INFO "adapter ID=%4X index=%d\n", - asihpi->hpi->adapter->type, adapter_index); - err = hpi_adapter_get_property(adapter_index, HPI_ADAPTER_PROPERTY_CAPS1, NULL, &asihpi->support_grouping); @@ -2968,22 +2963,21 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev, asihpi->in_min_chans = 1; } - snd_printk(KERN_INFO "update_interval_frames: %d", - asihpi->update_interval_frames); - snd_printk(KERN_INFO "Has dma:%d, grouping:%d, mrx:%d\n", + dev_info(&pci_dev->dev, "Has dma:%d, grouping:%d, mrx:%d, uif:%d\n", asihpi->can_dma, asihpi->support_grouping, - asihpi->support_mrx + asihpi->support_mrx, + asihpi->update_interval_frames ); err = snd_card_asihpi_pcm_new(asihpi, 0); if (err < 0) { - snd_printk(KERN_ERR "pcm_new failed\n"); + dev_err(&pci_dev->dev, "pcm_new failed\n"); goto __nodev; } err = snd_card_asihpi_mixer_new(asihpi); if (err < 0) { - snd_printk(KERN_ERR "mixer_new failed\n"); + dev_err(&pci_dev->dev, "mixer_new failed\n"); goto __nodev; } @@ -3015,7 +3009,7 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev, } __nodev: snd_card_free(card); - snd_printk(KERN_ERR "snd_asihpi_probe error %d\n", err); + dev_err(&pci_dev->dev, "snd_asihpi_probe error %d\n", err); return err; } -- cgit v1.2.3 From dc612838eac746b11bb4e5d923dafeea0ba7e81b Mon Sep 17 00:00:00 2001 From: Eliot Blennerhassett Date: Thu, 20 Nov 2014 16:22:56 +1300 Subject: ALSA: asihpi: don't fail probe if adapter mode read fails Only determining if low latency mode is enabled. Failure indicates adapter has no modes Signed-off-by: Eliot Blennerhassett Signed-off-by: Takashi Iwai --- sound/pci/asihpi/hpioctl.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c index 9454932fc9c0..e457eb80658b 100644 --- a/sound/pci/asihpi/hpioctl.c +++ b/sound/pci/asihpi/hpioctl.c @@ -424,14 +424,13 @@ int asihpi_adapter_probe(struct pci_dev *pci_dev, hm.adapter_index = adapter.adapter->index; hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); - if (hr.error) { - HPI_DEBUG_LOG(ERROR, - "HPI_ADAPTER_GET_MODE failed, aborting\n"); - goto err; - } - - if (hr.u.ax.mode.adapter_mode == HPI_ADAPTER_MODE_LOW_LATENCY) + if (!hr.error + && hr.u.ax.mode.adapter_mode == HPI_ADAPTER_MODE_LOW_LATENCY) low_latency_mode = 1; + else + dev_info(&pci_dev->dev, + "Adapter at index %d is not in low latency mode\n", + adapter.adapter->index); /* Check if IRQs are supported */ hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, -- cgit v1.2.3 From 51e6f47dd2e3463dac6f37128fd7b7cb40c500de Mon Sep 17 00:00:00 2001 From: Eliot Blennerhassett Date: Thu, 20 Nov 2014 16:22:57 +1300 Subject: ALSA: asihpi: used parts of message/response are zeroed before use Signed-off-by: Eliot Blennerhassett Signed-off-by: Takashi Iwai --- sound/pci/asihpi/hpimsginit.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/pci/asihpi/hpimsginit.c b/sound/pci/asihpi/hpimsginit.c index 032d563e3708..7eb617175fde 100644 --- a/sound/pci/asihpi/hpimsginit.c +++ b/sound/pci/asihpi/hpimsginit.c @@ -1,7 +1,7 @@ /****************************************************************************** AudioScience HPI driver - Copyright (C) 1997-2011 AudioScience Inc. + Copyright (C) 1997-2014 AudioScience Inc. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as @@ -37,11 +37,15 @@ static u16 gwSSX2_bypass; static void hpi_init_message(struct hpi_message *phm, u16 object, u16 function) { - memset(phm, 0, sizeof(*phm)); + u16 size; + if ((object > 0) && (object <= HPI_OBJ_MAXINDEX)) - phm->size = msg_size[object]; + size = msg_size[object]; else - phm->size = sizeof(*phm); + size = sizeof(*phm); + + memset(phm, 0, size); + phm->size = size; if (gwSSX2_bypass) phm->type = HPI_TYPE_SSX2BYPASS_MESSAGE; @@ -60,12 +64,16 @@ static void hpi_init_message(struct hpi_message *phm, u16 object, void hpi_init_response(struct hpi_response *phr, u16 object, u16 function, u16 error) { - memset(phr, 0, sizeof(*phr)); - phr->type = HPI_TYPE_RESPONSE; + u16 size; + if ((object > 0) && (object <= HPI_OBJ_MAXINDEX)) - phr->size = res_size[object]; + size = res_size[object]; else - phr->size = sizeof(*phr); + size = sizeof(*phr); + + memset(phr, 0, sizeof(*phr)); + phr->size = size; + phr->type = HPI_TYPE_RESPONSE; phr->object = object; phr->function = function; phr->error = error; @@ -86,7 +94,7 @@ void hpi_init_message_response(struct hpi_message *phm, static void hpi_init_messageV1(struct hpi_message_header *phm, u16 size, u16 object, u16 function) { - memset(phm, 0, sizeof(*phm)); + memset(phm, 0, size); if ((object > 0) && (object <= HPI_OBJ_MAXINDEX)) { phm->size = size; phm->type = HPI_TYPE_REQUEST; @@ -100,7 +108,9 @@ static void hpi_init_messageV1(struct hpi_message_header *phm, u16 size, void hpi_init_responseV1(struct hpi_response_header *phr, u16 size, u16 object, u16 function) { - memset(phr, 0, sizeof(*phr)); + (void)object; + (void)function; + memset(phr, 0, size); phr->size = size; phr->version = 1; phr->type = HPI_TYPE_RESPONSE; -- cgit v1.2.3 From 413cbf469a19e7662ba5025695bf5a573927105a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 1 Oct 2014 10:30:53 +0200 Subject: ALSA: hda - Limit 40bit DMA for AMD HDMI controllers AMD/ATI HDMI controller chip models, we already have a filter to lower to 32bit DMA, but the rest are supposed to be working with 64bit although the hardware doesn't really work with 63bit but only with 40 or 48bit DMA. In this patch, we take 40bit DMA for safety for the AMD/ATI controllers as the graphics drivers does. Signed-off-by: Takashi Iwai Signed-off-by: Benjamin Herrenschmidt CC: --- sound/pci/hda/hda_intel.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 16660f312043..bd298ba5d4df 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1486,6 +1486,7 @@ static int azx_first_init(struct azx *chip) struct snd_card *card = chip->card; int err; unsigned short gcap; + unsigned int dma_bits = 64; #if BITS_PER_LONG != 64 /* Fix up base address on ULI M5461 */ @@ -1522,9 +1523,14 @@ static int azx_first_init(struct azx *chip) gcap = azx_readw(chip, GCAP); dev_dbg(card->dev, "chipset global capabilities = 0x%x\n", gcap); + /* AMD devices support 40 or 48bit DMA, take the safe one */ + if (chip->pci->vendor == PCI_VENDOR_ID_AMD) + dma_bits = 40; + /* disable SB600 64bit support for safety */ if (chip->pci->vendor == PCI_VENDOR_ID_ATI) { struct pci_dev *p_smbus; + dma_bits = 40; p_smbus = pci_get_device(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS, NULL); @@ -1554,9 +1560,11 @@ static int azx_first_init(struct azx *chip) } /* allow 64bit DMA address if supported by H/W */ - if ((gcap & AZX_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64))) - pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(64)); - else { + if (!(gcap & AZX_GCAP_64OK)) + dma_bits = 32; + if (!pci_set_dma_mask(pci, DMA_BIT_MASK(dma_bits))) { + pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(dma_bits)); + } else { pci_set_dma_mask(pci, DMA_BIT_MASK(32)); pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32)); } -- cgit v1.2.3 From db79afa1e57925ba96ab18514c0ebe42a28e393e Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 24 Nov 2014 14:17:08 +1100 Subject: sound/radeon: Move 64-bit MSI quirk from arch to driver A number of radeon cards have a HW limitation causing them to be unable to generate the full 64-bit of address bits for MSIs. This breaks MSIs on some platforms such as POWER machines. We used to have a powerpc specific quirk to address that on a single card, but this doesn't scale very well, this is better put under control of the drivers who know precisely what a given HW revision can do. We now have a generic quirk in the PCI code. We should set it appropriately for all radeon's from the audio driver. Signed-off-by: Benjamin Herrenschmidt Reviewed-by: Takashi Iwai Reviewed-by: Alex Deucher CC: --- sound/pci/hda/hda_intel.c | 10 ++++++++-- sound/pci/hda/hda_priv.h | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index bd298ba5d4df..48b6c5a3884f 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -298,7 +298,8 @@ enum { /* quirks for ATI/AMD HDMI */ #define AZX_DCAPS_PRESET_ATI_HDMI \ - (AZX_DCAPS_NO_TCSEL | AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB) + (AZX_DCAPS_NO_TCSEL | AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB|\ + AZX_DCAPS_NO_MSI64) /* quirks for Nvidia */ #define AZX_DCAPS_PRESET_NVIDIA \ @@ -1510,9 +1511,14 @@ static int azx_first_init(struct azx *chip) return -ENXIO; } - if (chip->msi) + if (chip->msi) { + if (chip->driver_caps & AZX_DCAPS_NO_MSI64) { + dev_dbg(card->dev, "Disabling 64bit MSI\n"); + pci->no_64bit_msi = true; + } if (pci_enable_msi(pci) < 0) chip->msi = 0; + } if (azx_acquire_irq(chip, 0) < 0) return -EBUSY; diff --git a/sound/pci/hda/hda_priv.h b/sound/pci/hda/hda_priv.h index 949cd437eeb2..5016014e57f2 100644 --- a/sound/pci/hda/hda_priv.h +++ b/sound/pci/hda/hda_priv.h @@ -171,6 +171,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */ #define AZX_DCAPS_I915_POWERWELL (1 << 27) /* HSW i915 powerwell support */ #define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28) /* CORBRP clears itself after reset */ +#define AZX_DCAPS_NO_MSI64 (1 << 29) /* Stick to 32-bit MSIs */ /* HD Audio class code */ #define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403 -- cgit v1.2.3 From 69eba10e606a80665f8573221fec589430d9d1cb Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 27 Nov 2014 01:34:43 +0300 Subject: ALSA: hda - using uninitialized data In olden times the snd_hda_param_read() function always set "*start_id" but in 2007 we introduced a new return and it causes uninitialized data bugs in a couple of the callers: print_codec_info() and hdmi_parse_codec(). Fixes: e8a7f136f5ed ('[ALSA] hda-intel - Improve HD-audio codec probing robustness') Signed-off-by: Dan Carpenter Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index b2d58998dbdd..2fe86d2e1b09 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -346,8 +346,10 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, unsigned int parm; parm = snd_hda_param_read(codec, nid, AC_PAR_NODE_COUNT); - if (parm == -1) + if (parm == -1) { + *start_id = 0; return 0; + } *start_id = (parm >> 16) & 0x7fff; return (int)(parm & 0x7fff); } -- cgit v1.2.3 From 37e661ee10c6d0d1310c62b3d29ae9a63073ac5d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 25 Nov 2014 11:28:07 +0100 Subject: ALSA: hda - Add AZX_DCAPS_SNOOP_OFF (and refactor snoop setup) Add a new driver_caps bit, AZX_DCAPS_SNOOP_OFF, to set the snoop off as default. This new bit is used for the checks in azx_check_snoop_available(). Most of case-switches are replaced with the new dcaps in each entry. While working on it, for avoiding to spend more bits, combine three bits AZX_DCAPS_SNOOP_SCH, AZX_DCAPS_SNOOP_ATI and AZX_DCAPS_SNOOP_NVIDIA bits into a flat type of two bits. This reduces the bits usages, and assign AZX_DCAPS_OFF to this empty bit now. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 71 +++++++++++++++++++++++++---------------------- sound/pci/hda/hda_priv.h | 12 ++++++-- 2 files changed, 47 insertions(+), 36 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 966e6f98892d..633020de9bd2 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -272,42 +272,51 @@ enum { AZX_NUM_DRIVERS, /* keep this as last entry */ }; +#define azx_get_snoop_type(chip) \ + (((chip)->driver_caps & AZX_DCAPS_SNOOP_MASK) >> 10) +#define AZX_DCAPS_SNOOP_TYPE(type) ((AZX_SNOOP_TYPE_ ## type) << 10) + /* quirks for Intel PCH */ #define AZX_DCAPS_INTEL_PCH_NOPM \ - (AZX_DCAPS_SCH_SNOOP | AZX_DCAPS_BUFSIZE | \ - AZX_DCAPS_COUNT_LPIB_DELAY | AZX_DCAPS_REVERSE_ASSIGN) + (AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY |\ + AZX_DCAPS_REVERSE_ASSIGN | AZX_DCAPS_SNOOP_TYPE(SCH)) #define AZX_DCAPS_INTEL_PCH \ (AZX_DCAPS_INTEL_PCH_NOPM | AZX_DCAPS_PM_RUNTIME) #define AZX_DCAPS_INTEL_HASWELL \ - (AZX_DCAPS_SCH_SNOOP | AZX_DCAPS_ALIGN_BUFSIZE | \ - AZX_DCAPS_COUNT_LPIB_DELAY | AZX_DCAPS_PM_RUNTIME | \ - AZX_DCAPS_I915_POWERWELL) + (AZX_DCAPS_ALIGN_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY |\ + AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_POWERWELL |\ + AZX_DCAPS_SNOOP_TYPE(SCH)) /* Broadwell HDMI can't use position buffer reliably, force to use LPIB */ #define AZX_DCAPS_INTEL_BROADWELL \ - (AZX_DCAPS_SCH_SNOOP | AZX_DCAPS_ALIGN_BUFSIZE | \ - AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_PM_RUNTIME | \ - AZX_DCAPS_I915_POWERWELL) + (AZX_DCAPS_ALIGN_BUFSIZE | AZX_DCAPS_POSFIX_LPIB |\ + AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_POWERWELL |\ + AZX_DCAPS_SNOOP_TYPE(SCH)) /* quirks for ATI SB / AMD Hudson */ #define AZX_DCAPS_PRESET_ATI_SB \ - (AZX_DCAPS_ATI_SNOOP | AZX_DCAPS_NO_TCSEL | \ - AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB) + (AZX_DCAPS_NO_TCSEL | AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB |\ + AZX_DCAPS_SNOOP_TYPE(ATI)) /* quirks for ATI/AMD HDMI */ #define AZX_DCAPS_PRESET_ATI_HDMI \ (AZX_DCAPS_NO_TCSEL | AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB) +/* quirks for ATI HDMI with snoop off */ +#define AZX_DCAPS_PRESET_ATI_HDMI_NS \ + (AZX_DCAPS_PRESET_ATI_HDMI | AZX_DCAPS_SNOOP_OFF) + /* quirks for Nvidia */ #define AZX_DCAPS_PRESET_NVIDIA \ - (AZX_DCAPS_NVIDIA_SNOOP | AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI |\ - AZX_DCAPS_ALIGN_BUFSIZE | AZX_DCAPS_NO_64BIT |\ - AZX_DCAPS_CORBRP_SELF_CLEAR) + (AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI | AZX_DCAPS_ALIGN_BUFSIZE |\ + AZX_DCAPS_NO_64BIT | AZX_DCAPS_CORBRP_SELF_CLEAR |\ + AZX_DCAPS_SNOOP_TYPE(NVIDIA)) #define AZX_DCAPS_PRESET_CTHDA \ - (AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_4K_BDLE_BOUNDARY) + (AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB |\ + AZX_DCAPS_4K_BDLE_BOUNDARY | AZX_DCAPS_SNOOP_OFF) /* * VGA-switcher support @@ -436,6 +445,8 @@ static void update_pci_byte(struct pci_dev *pci, unsigned int reg, static void azx_init_pci(struct azx *chip) { + int snoop_type = azx_get_snoop_type(chip); + /* Clear bits 0-2 of PCI register TCSEL (at offset 0x44) * TCSEL == Traffic Class Select Register, which sets PCI express QOS * Ensuring these bits are 0 clears playback static on some HD Audio @@ -450,7 +461,7 @@ static void azx_init_pci(struct azx *chip) /* For ATI SB450/600/700/800/900 and AMD Hudson azalia HD audio, * we need to enable snoop. */ - if (chip->driver_caps & AZX_DCAPS_ATI_SNOOP) { + if (snoop_type == AZX_SNOOP_TYPE_ATI) { dev_dbg(chip->card->dev, "Setting ATI snoop: %d\n", azx_snoop(chip)); update_pci_byte(chip->pci, @@ -459,7 +470,7 @@ static void azx_init_pci(struct azx *chip) } /* For NVIDIA HDA, enable snoop */ - if (chip->driver_caps & AZX_DCAPS_NVIDIA_SNOOP) { + if (snoop_type == AZX_SNOOP_TYPE_NVIDIA) { dev_dbg(chip->card->dev, "Setting Nvidia snoop: %d\n", azx_snoop(chip)); update_pci_byte(chip->pci, @@ -474,7 +485,7 @@ static void azx_init_pci(struct azx *chip) } /* Enable SCH/PCH snoop if needed */ - if (chip->driver_caps & AZX_DCAPS_SCH_SNOOP) { + if (snoop_type == AZX_SNOOP_TYPE_SCH) { unsigned short snoop; pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop); if ((!azx_snoop(chip) && !(snoop & INTEL_SCH_HDA_DEVC_NOSNOOP)) || @@ -1361,8 +1372,8 @@ static void azx_check_snoop_available(struct azx *chip) { bool snoop = chip->snoop; - switch (chip->driver_type) { - case AZX_DRIVER_VIA: + if (azx_get_snoop_type(chip) == AZX_SNOOP_TYPE_NONE && + chip->driver_type == AZX_DRIVER_VIA) { /* force to non-snoop mode for a new VIA controller * when BIOS is set */ @@ -1372,17 +1383,11 @@ static void azx_check_snoop_available(struct azx *chip) if (!(val & 0x80) && chip->pci->revision == 0x30) snoop = false; } - break; - case AZX_DRIVER_ATIHDMI_NS: - /* new ATI HDMI requires non-snoop */ - snoop = false; - break; - case AZX_DRIVER_CTHDA: - case AZX_DRIVER_CMEDIA: - snoop = false; - break; } + if (chip->driver_caps & AZX_DCAPS_SNOOP_OFF) + snoop = false; + if (snoop != chip->snoop) { dev_info(chip->card->dev, "Force to %s mode\n", snoop ? "snoop" : "non-snoop"); @@ -2116,13 +2121,13 @@ static const struct pci_device_id azx_ids[] = { { PCI_DEVICE(0x1002, 0xaa98), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, { PCI_DEVICE(0x1002, 0x9902), - .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI }, + .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, { PCI_DEVICE(0x1002, 0xaaa0), - .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI }, + .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, { PCI_DEVICE(0x1002, 0xaaa8), - .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI }, + .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, { PCI_DEVICE(0x1002, 0xaab0), - .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI }, + .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, /* VIA VT8251/VT8237A */ { PCI_DEVICE(0x1106, 0x3288), .driver_data = AZX_DRIVER_VIA | AZX_DCAPS_POSFIX_VIA }, @@ -2169,7 +2174,7 @@ static const struct pci_device_id azx_ids[] = { /* CM8888 */ { PCI_DEVICE(0x13f6, 0x5011), .driver_data = AZX_DRIVER_CMEDIA | - AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB }, + AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_SNOOP_OFF }, /* Vortex86MX */ { PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC }, /* VMware HDAudio */ diff --git a/sound/pci/hda/hda_priv.h b/sound/pci/hda/hda_priv.h index 949cd437eeb2..602536c2147d 100644 --- a/sound/pci/hda/hda_priv.h +++ b/sound/pci/hda/hda_priv.h @@ -152,9 +152,8 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; /* bits 0-7 are used for indicating driver type */ #define AZX_DCAPS_NO_TCSEL (1 << 8) /* No Intel TCSEL bit */ #define AZX_DCAPS_NO_MSI (1 << 9) /* No MSI support */ -#define AZX_DCAPS_ATI_SNOOP (1 << 10) /* ATI snoop enable */ -#define AZX_DCAPS_NVIDIA_SNOOP (1 << 11) /* Nvidia snoop enable */ -#define AZX_DCAPS_SCH_SNOOP (1 << 12) /* SCH/PCH snoop enable */ +#define AZX_DCAPS_SNOOP_MASK (3 << 10) /* snoop type mask */ +#define AZX_DCAPS_SNOOP_OFF (1 << 12) /* snoop default off */ #define AZX_DCAPS_RIRB_DELAY (1 << 13) /* Long delay in read loop */ #define AZX_DCAPS_RIRB_PRE_DELAY (1 << 14) /* Put a delay before read */ #define AZX_DCAPS_CTX_WORKAROUND (1 << 15) /* X-Fi workaround */ @@ -172,6 +171,13 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define AZX_DCAPS_I915_POWERWELL (1 << 27) /* HSW i915 powerwell support */ #define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28) /* CORBRP clears itself after reset */ +enum { + AZX_SNOOP_TYPE_NONE , + AZX_SNOOP_TYPE_SCH, + AZX_SNOOP_TYPE_ATI, + AZX_SNOOP_TYPE_NVIDIA, +}; + /* HD Audio class code */ #define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403 -- cgit v1.2.3 From 7c7320157a37ed459b59e2f6b53b73780b12ad80 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 25 Nov 2014 12:54:16 +0100 Subject: ALSA: hda - Allow forcibly enabling/disabling snoop User can pass snoop option to enable/disable the snoop behavior, but currently azx_check_snoop_available() always turns it off for some devices. For better debuggability, change the parameter as bint, and allow user to enable/disable forcibly the snoop when specified via the module option. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 633020de9bd2..728663d6746f 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -196,8 +196,8 @@ MODULE_PARM_DESC(align_buffer_size, "Force buffer and period sizes to be multiple of 128 bytes."); #ifdef CONFIG_X86 -static bool hda_snoop = true; -module_param_named(snoop, hda_snoop, bool, 0444); +static int hda_snoop = -1; +module_param_named(snoop, hda_snoop, bint, 0444); MODULE_PARM_DESC(snoop, "Enable/disable snooping"); #else #define hda_snoop true @@ -1370,29 +1370,33 @@ static void check_msi(struct azx *chip) /* check the snoop mode availability */ static void azx_check_snoop_available(struct azx *chip) { - bool snoop = chip->snoop; + int snoop = hda_snoop; + if (snoop >= 0) { + dev_info(chip->card->dev, "Force to %s mode by module option\n", + snoop ? "snoop" : "non-snoop"); + chip->snoop = snoop; + return; + } + + snoop = true; if (azx_get_snoop_type(chip) == AZX_SNOOP_TYPE_NONE && chip->driver_type == AZX_DRIVER_VIA) { /* force to non-snoop mode for a new VIA controller * when BIOS is set */ - if (snoop) { - u8 val; - pci_read_config_byte(chip->pci, 0x42, &val); - if (!(val & 0x80) && chip->pci->revision == 0x30) - snoop = false; - } + u8 val; + pci_read_config_byte(chip->pci, 0x42, &val); + if (!(val & 0x80) && chip->pci->revision == 0x30) + snoop = false; } if (chip->driver_caps & AZX_DCAPS_SNOOP_OFF) snoop = false; - if (snoop != chip->snoop) { - dev_info(chip->card->dev, "Force to %s mode\n", - snoop ? "snoop" : "non-snoop"); - chip->snoop = snoop; - } + chip->snoop = snoop; + if (!snoop) + dev_info(chip->card->dev, "Force to non-snoop mode\n"); } static void azx_probe_work(struct work_struct *work) @@ -1452,7 +1456,6 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci, check_probe_mask(chip, dev); chip->single_cmd = single_cmd; - chip->snoop = hda_snoop; azx_check_snoop_available(chip); if (bdl_pos_adj[dev] < 0) { -- cgit v1.2.3 From 7a2e9ddc903225d8fb3a510a842144a239017ee4 Mon Sep 17 00:00:00 2001 From: Jurgen Kramer Date: Fri, 28 Nov 2014 17:32:53 +0100 Subject: ALSA: usb-audio: Add native DSD support for Denon/Marantz DACs This patch adds native DSD support for the following devices: - Marantz SA-14S1 - Marants HD-DAC1 Signed-off-by: Jurgen Kramer Signed-off-by: Takashi Iwai --- sound/usb/quirks.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'sound') diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 2c1018e447b1..a9d4add89bbe 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1213,5 +1213,16 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, break; } + /* Denon/Marantz devices with USB DAC functionality */ + switch (chip->usb_id) { + case USB_ID(0x154e, 0x3005): /* Marantz HD-DAC1 */ + case USB_ID(0x154e, 0x3006): /* Marantz SA-14S1 */ + if (fp->altsetting == 2) + return SNDRV_PCM_FMTBIT_DSD_U32_BE; + break; + default: + break; + } + return 0; } -- cgit v1.2.3 From 6874daad4b0fbed5b2f9bef7f4d3f2b895463a95 Mon Sep 17 00:00:00 2001 From: Jurgen Kramer Date: Fri, 28 Nov 2014 17:32:54 +0100 Subject: ALSA: usb-audio: Add mode select quirk for Denon/Marantz DACs Denon/Marantz USB DACs need a specific vendor command to switch between PCM and DSD mode. This patch adds a new quirk function to switch between the two modes using the specific USB vendor command. This patch applies to the following devices: - Marantz SA-14S1 - Marantz HD-DAC1 Signed-off-by: Jurgen Kramer Signed-off-by: Takashi Iwai --- sound/usb/pcm.c | 5 +++++ sound/usb/quirks.c | 38 ++++++++++++++++++++++++++++++++++++++ sound/usb/quirks.h | 3 +++ 3 files changed, 46 insertions(+) (limited to 'sound') diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index c62a1659106d..0d8aba5fe1a8 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -482,6 +482,11 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) /* set interface */ if (subs->interface != fmt->iface || subs->altset_idx != fmt->altset_idx) { + + err = snd_usb_select_mode_quirk(subs, fmt); + if (err < 0) + return -EIO; + err = usb_set_interface(dev, fmt->iface, fmt->altsetting); if (err < 0) { dev_err(&dev->dev, diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index a9d4add89bbe..e0cde741e41d 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1111,6 +1111,44 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs, } } + +/* Marantz/Denon USB DACs need a vendor cmd to switch + * between PCM and native DSD mode + */ +int snd_usb_select_mode_quirk(struct snd_usb_substream *subs, + struct audioformat *fmt) +{ + struct usb_device *dev = subs->dev; + int err; + + switch (subs->stream->chip->usb_id) { + case USB_ID(0x154e, 0x3005): /* Marantz HD-DAC1 */ + case USB_ID(0x154e, 0x3006): /* Marantz SA-14S1 */ + + /* First switch to alt set 0, otherwise the mode switch cmd + * will not be accepted by the DAC + */ + err = usb_set_interface(dev, fmt->iface, 0); + if (err < 0) + return err; + + mdelay(20); /* Delay needed after setting the interface */ + + switch (fmt->altsetting) { + case 2: /* DSD mode requested */ + case 1: /* PCM mode requested */ + err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 0, + USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, + fmt->altsetting - 1, 1, NULL, 0); + if (err < 0) + return err; + break; + } + mdelay(20); + } + return 0; +} + void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep) { /* diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h index 665e972a1b40..1b862386577d 100644 --- a/sound/usb/quirks.h +++ b/sound/usb/quirks.h @@ -31,6 +31,9 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size); +int snd_usb_select_mode_quirk(struct snd_usb_substream *subs, + struct audioformat *fmt); + u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, struct audioformat *fp, unsigned int sample_bytes); -- cgit v1.2.3 From 81fc5ad51539e765cd470f1d0d9d0477d1c4c30c Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sat, 29 Nov 2014 00:59:10 +0900 Subject: ALSA: dice: suppress checkpatch.pl warnings The checkpatch.pl generates some warnings due to: - C99 comment - a line over 80 characters - min() for parameters with different types Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/dice.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/firewire/dice.c b/sound/firewire/dice.c index e3a04d69c853..72af110d0f98 100644 --- a/sound/firewire/dice.c +++ b/sound/firewire/dice.c @@ -133,7 +133,7 @@ static inline u64 global_address(struct dice *dice, unsigned int offset) return DICE_PRIVATE_SPACE + dice->global_offset + offset; } -// TODO: rx index +/* TODO: rx index */ static inline u64 rx_address(struct dice *dice, unsigned int offset) { return DICE_PRIVATE_SPACE + dice->rx_offset + offset; @@ -721,13 +721,14 @@ static long dice_hwdep_read(struct snd_hwdep *hwdep, char __user *buf, event.lock_status.status = dice->dev_lock_count > 0; dice->dev_lock_changed = false; - count = min(count, (long)sizeof(event.lock_status)); + count = min_t(long, count, sizeof(event.lock_status)); } else { - event.dice_notification.type = SNDRV_FIREWIRE_EVENT_DICE_NOTIFICATION; + event.dice_notification.type = + SNDRV_FIREWIRE_EVENT_DICE_NOTIFICATION; event.dice_notification.notification = dice->notification_bits; dice->notification_bits = 0; - count = min(count, (long)sizeof(event.dice_notification)); + count = min_t(long, count, sizeof(event.dice_notification)); } spin_unlock_irq(&dice->lock); -- cgit v1.2.3 From 732d153fbeac1774393508b3cec4b1d09e567585 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sat, 29 Nov 2014 00:59:11 +0900 Subject: ALSA: dice: Rename structure and its members Currently, dice driver supports AMDTP out-stream. In followed commits, AMDTP in-stream will be supported but current name of members in dice structure are not propper. This commit renames these members to proper name. Additionally, for easily distinguishing local symbols from structure tag, rename dice tag into snd_dice. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/dice.c | 162 +++++++++++++++++++++++++------------------------- 1 file changed, 81 insertions(+), 81 deletions(-) (limited to 'sound') diff --git a/sound/firewire/dice.c b/sound/firewire/dice.c index 72af110d0f98..eafd74b97376 100644 --- a/sound/firewire/dice.c +++ b/sound/firewire/dice.c @@ -32,7 +32,7 @@ #include "dice-interface.h" -struct dice { +struct snd_dice { struct snd_card *card; struct fw_unit *unit; spinlock_t lock; @@ -50,8 +50,8 @@ struct dice { struct completion clock_accepted; wait_queue_head_t hwdep_wait; u32 notification_bits; - struct fw_iso_resources resources; - struct amdtp_stream stream; + struct fw_iso_resources rx_resources; + struct amdtp_stream rx_stream; }; MODULE_DESCRIPTION("DICE driver"); @@ -87,13 +87,13 @@ static unsigned int rate_index_to_mode(unsigned int rate_index) return ((int)rate_index - 1) / 2; } -static void dice_lock_changed(struct dice *dice) +static void dice_lock_changed(struct snd_dice *dice) { dice->dev_lock_changed = true; wake_up(&dice->hwdep_wait); } -static int dice_try_lock(struct dice *dice) +static int dice_try_lock(struct snd_dice *dice) { int err; @@ -114,7 +114,7 @@ out: return err; } -static void dice_unlock(struct dice *dice) +static void dice_unlock(struct snd_dice *dice) { spin_lock_irq(&dice->lock); @@ -128,18 +128,18 @@ out: spin_unlock_irq(&dice->lock); } -static inline u64 global_address(struct dice *dice, unsigned int offset) +static inline u64 global_address(struct snd_dice *dice, unsigned int offset) { return DICE_PRIVATE_SPACE + dice->global_offset + offset; } /* TODO: rx index */ -static inline u64 rx_address(struct dice *dice, unsigned int offset) +static inline u64 rx_address(struct snd_dice *dice, unsigned int offset) { return DICE_PRIVATE_SPACE + dice->rx_offset + offset; } -static int dice_owner_set(struct dice *dice) +static int dice_owner_set(struct snd_dice *dice) { struct fw_device *device = fw_parent_device(dice->unit); __be64 *buffer; @@ -183,7 +183,7 @@ static int dice_owner_set(struct dice *dice) return err; } -static int dice_owner_update(struct dice *dice) +static int dice_owner_update(struct snd_dice *dice) { struct fw_device *device = fw_parent_device(dice->unit); __be64 *buffer; @@ -226,7 +226,7 @@ static int dice_owner_update(struct dice *dice) return err; } -static void dice_owner_clear(struct dice *dice) +static void dice_owner_clear(struct snd_dice *dice) { struct fw_device *device = fw_parent_device(dice->unit); __be64 *buffer; @@ -249,7 +249,7 @@ static void dice_owner_clear(struct dice *dice) dice->owner_generation = -1; } -static int dice_enable_set(struct dice *dice) +static int dice_enable_set(struct snd_dice *dice) { __be32 value; int err; @@ -267,7 +267,7 @@ static int dice_enable_set(struct dice *dice) return 0; } -static void dice_enable_clear(struct dice *dice) +static void dice_enable_clear(struct snd_dice *dice) { __be32 value; @@ -288,7 +288,7 @@ static void dice_notification(struct fw_card *card, struct fw_request *request, int generation, unsigned long long offset, void *data, size_t length, void *callback_data) { - struct dice *dice = callback_data; + struct snd_dice *dice = callback_data; u32 bits; unsigned long flags; @@ -317,7 +317,7 @@ static void dice_notification(struct fw_card *card, struct fw_request *request, static int dice_rate_constraint(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { - struct dice *dice = rule->private; + struct snd_dice *dice = rule->private; const struct snd_interval *channels = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS); struct snd_interval *rate = @@ -344,7 +344,7 @@ static int dice_rate_constraint(struct snd_pcm_hw_params *params, static int dice_channels_constraint(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { - struct dice *dice = rule->private; + struct snd_dice *dice = rule->private; const struct snd_interval *rate = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE); struct snd_interval *channels = @@ -384,7 +384,7 @@ static int dice_open(struct snd_pcm_substream *substream) .periods_min = 1, .periods_max = UINT_MAX, }; - struct dice *dice = substream->private_data; + struct snd_dice *dice = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; unsigned int i; int err; @@ -420,7 +420,7 @@ static int dice_open(struct snd_pcm_substream *substream) if (err < 0) goto err_lock; - err = amdtp_stream_add_pcm_hw_constraints(&dice->stream, runtime); + err = amdtp_stream_add_pcm_hw_constraints(&dice->rx_stream, runtime); if (err < 0) goto err_lock; @@ -434,47 +434,47 @@ error: static int dice_close(struct snd_pcm_substream *substream) { - struct dice *dice = substream->private_data; + struct snd_dice *dice = substream->private_data; dice_unlock(dice); return 0; } -static int dice_stream_start_packets(struct dice *dice) +static int dice_stream_start_packets(struct snd_dice *dice) { int err; - if (amdtp_stream_running(&dice->stream)) + if (amdtp_stream_running(&dice->rx_stream)) return 0; - err = amdtp_stream_start(&dice->stream, dice->resources.channel, + err = amdtp_stream_start(&dice->rx_stream, dice->rx_resources.channel, fw_parent_device(dice->unit)->max_speed); if (err < 0) return err; err = dice_enable_set(dice); if (err < 0) { - amdtp_stream_stop(&dice->stream); + amdtp_stream_stop(&dice->rx_stream); return err; } return 0; } -static int dice_stream_start(struct dice *dice) +static int dice_stream_start(struct snd_dice *dice) { __be32 channel; int err; - if (!dice->resources.allocated) { - err = fw_iso_resources_allocate(&dice->resources, - amdtp_stream_get_max_payload(&dice->stream), + if (!dice->rx_resources.allocated) { + err = fw_iso_resources_allocate(&dice->rx_resources, + amdtp_stream_get_max_payload(&dice->rx_stream), fw_parent_device(dice->unit)->max_speed); if (err < 0) goto error; - channel = cpu_to_be32(dice->resources.channel); + channel = cpu_to_be32(dice->rx_resources.channel); err = snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST, rx_address(dice, RX_ISOCHRONOUS), @@ -494,36 +494,36 @@ err_rx_channel: snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST, rx_address(dice, RX_ISOCHRONOUS), &channel, 4, 0); err_resources: - fw_iso_resources_free(&dice->resources); + fw_iso_resources_free(&dice->rx_resources); error: return err; } -static void dice_stream_stop_packets(struct dice *dice) +static void dice_stream_stop_packets(struct snd_dice *dice) { - if (amdtp_stream_running(&dice->stream)) { + if (amdtp_stream_running(&dice->rx_stream)) { dice_enable_clear(dice); - amdtp_stream_stop(&dice->stream); + amdtp_stream_stop(&dice->rx_stream); } } -static void dice_stream_stop(struct dice *dice) +static void dice_stream_stop(struct snd_dice *dice) { __be32 channel; dice_stream_stop_packets(dice); - if (!dice->resources.allocated) + if (!dice->rx_resources.allocated) return; channel = cpu_to_be32((u32)-1); snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST, rx_address(dice, RX_ISOCHRONOUS), &channel, 4, 0); - fw_iso_resources_free(&dice->resources); + fw_iso_resources_free(&dice->rx_resources); } -static int dice_change_rate(struct dice *dice, unsigned int clock_rate) +static int dice_change_rate(struct snd_dice *dice, unsigned int clock_rate) { __be32 value; int err; @@ -547,7 +547,7 @@ static int dice_change_rate(struct dice *dice, unsigned int clock_rate) static int dice_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { - struct dice *dice = substream->private_data; + struct snd_dice *dice = substream->private_data; unsigned int rate_index, mode, rate, channels, i; int err; @@ -585,24 +585,24 @@ static int dice_hw_params(struct snd_pcm_substream *substream, rate /= 2; channels *= 2; - dice->stream.double_pcm_frames = true; + dice->rx_stream.double_pcm_frames = true; } else { - dice->stream.double_pcm_frames = false; + dice->rx_stream.double_pcm_frames = false; } mode = rate_index_to_mode(rate_index); - amdtp_stream_set_parameters(&dice->stream, rate, channels, + amdtp_stream_set_parameters(&dice->rx_stream, rate, channels, dice->rx_midi_ports[mode]); if (rate_index > 4) { channels /= 2; for (i = 0; i < channels; i++) { - dice->stream.pcm_positions[i] = i * 2; - dice->stream.pcm_positions[i + channels] = i * 2 + 1; + dice->rx_stream.pcm_positions[i] = i * 2; + dice->rx_stream.pcm_positions[i + channels] = i * 2 + 1; } } - amdtp_stream_set_pcm_format(&dice->stream, + amdtp_stream_set_pcm_format(&dice->rx_stream, params_format(hw_params)); return 0; @@ -610,7 +610,7 @@ static int dice_hw_params(struct snd_pcm_substream *substream, static int dice_hw_free(struct snd_pcm_substream *substream) { - struct dice *dice = substream->private_data; + struct snd_dice *dice = substream->private_data; mutex_lock(&dice->mutex); dice_stream_stop(dice); @@ -621,12 +621,12 @@ static int dice_hw_free(struct snd_pcm_substream *substream) static int dice_prepare(struct snd_pcm_substream *substream) { - struct dice *dice = substream->private_data; + struct snd_dice *dice = substream->private_data; int err; mutex_lock(&dice->mutex); - if (amdtp_streaming_error(&dice->stream)) + if (amdtp_streaming_error(&dice->rx_stream)) dice_stream_stop_packets(dice); err = dice_stream_start(dice); @@ -637,14 +637,14 @@ static int dice_prepare(struct snd_pcm_substream *substream) mutex_unlock(&dice->mutex); - amdtp_stream_pcm_prepare(&dice->stream); + amdtp_stream_pcm_prepare(&dice->rx_stream); return 0; } static int dice_trigger(struct snd_pcm_substream *substream, int cmd) { - struct dice *dice = substream->private_data; + struct snd_dice *dice = substream->private_data; struct snd_pcm_substream *pcm; switch (cmd) { @@ -657,19 +657,19 @@ static int dice_trigger(struct snd_pcm_substream *substream, int cmd) default: return -EINVAL; } - amdtp_stream_pcm_trigger(&dice->stream, pcm); + amdtp_stream_pcm_trigger(&dice->rx_stream, pcm); return 0; } static snd_pcm_uframes_t dice_pointer(struct snd_pcm_substream *substream) { - struct dice *dice = substream->private_data; + struct snd_dice *dice = substream->private_data; - return amdtp_stream_pcm_pointer(&dice->stream); + return amdtp_stream_pcm_pointer(&dice->rx_stream); } -static int dice_create_pcm(struct dice *dice) +static int dice_create_pcm(struct snd_dice *dice) { static struct snd_pcm_ops ops = { .open = dice_open, @@ -699,7 +699,7 @@ static int dice_create_pcm(struct dice *dice) static long dice_hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count, loff_t *offset) { - struct dice *dice = hwdep->private_data; + struct snd_dice *dice = hwdep->private_data; DEFINE_WAIT(wait); union snd_firewire_event event; @@ -742,7 +742,7 @@ static long dice_hwdep_read(struct snd_hwdep *hwdep, char __user *buf, static unsigned int dice_hwdep_poll(struct snd_hwdep *hwdep, struct file *file, poll_table *wait) { - struct dice *dice = hwdep->private_data; + struct snd_dice *dice = hwdep->private_data; unsigned int events; poll_wait(file, &dice->hwdep_wait, wait); @@ -757,7 +757,7 @@ static unsigned int dice_hwdep_poll(struct snd_hwdep *hwdep, struct file *file, return events; } -static int dice_hwdep_get_info(struct dice *dice, void __user *arg) +static int dice_hwdep_get_info(struct snd_dice *dice, void __user *arg) { struct fw_device *dev = fw_parent_device(dice->unit); struct snd_firewire_get_info info; @@ -776,7 +776,7 @@ static int dice_hwdep_get_info(struct dice *dice, void __user *arg) return 0; } -static int dice_hwdep_lock(struct dice *dice) +static int dice_hwdep_lock(struct snd_dice *dice) { int err; @@ -794,7 +794,7 @@ static int dice_hwdep_lock(struct dice *dice) return err; } -static int dice_hwdep_unlock(struct dice *dice) +static int dice_hwdep_unlock(struct snd_dice *dice) { int err; @@ -814,7 +814,7 @@ static int dice_hwdep_unlock(struct dice *dice) static int dice_hwdep_release(struct snd_hwdep *hwdep, struct file *file) { - struct dice *dice = hwdep->private_data; + struct snd_dice *dice = hwdep->private_data; spin_lock_irq(&dice->lock); if (dice->dev_lock_count == -1) @@ -827,7 +827,7 @@ static int dice_hwdep_release(struct snd_hwdep *hwdep, struct file *file) static int dice_hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file, unsigned int cmd, unsigned long arg) { - struct dice *dice = hwdep->private_data; + struct snd_dice *dice = hwdep->private_data; switch (cmd) { case SNDRV_FIREWIRE_IOCTL_GET_INFO: @@ -852,7 +852,7 @@ static int dice_hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file, #define dice_hwdep_compat_ioctl NULL #endif -static int dice_create_hwdep(struct dice *dice) +static int dice_create_hwdep(struct snd_dice *dice) { static const struct snd_hwdep_ops ops = { .read = dice_hwdep_read, @@ -876,7 +876,7 @@ static int dice_create_hwdep(struct dice *dice) return 0; } -static int dice_proc_read_mem(struct dice *dice, void *buffer, +static int dice_proc_read_mem(struct snd_dice *dice, void *buffer, unsigned int offset_q, unsigned int quadlets) { unsigned int i; @@ -899,8 +899,8 @@ static const char *str_from_array(const char *const strs[], unsigned int count, { if (i < count) return strs[i]; - else - return "(unknown)"; + + return "(unknown)"; } static void dice_proc_fixup_string(char *s, unsigned int size) @@ -935,7 +935,7 @@ static void dice_proc_read(struct snd_info_entry *entry, "32000", "44100", "48000", "88200", "96000", "176400", "192000", "any low", "any mid", "any high", "none" }; - struct dice *dice = entry->private_data; + struct snd_dice *dice = entry->private_data; u32 sections[ARRAY_SIZE(section_names) * 2]; struct { u32 number; @@ -1110,7 +1110,7 @@ static void dice_proc_read(struct snd_info_entry *entry, } } -static void dice_create_proc(struct dice *dice) +static void dice_create_proc(struct snd_dice *dice) { struct snd_info_entry *entry; @@ -1120,9 +1120,9 @@ static void dice_create_proc(struct dice *dice) static void dice_card_free(struct snd_card *card) { - struct dice *dice = card->private_data; + struct snd_dice *dice = card->private_data; - amdtp_stream_destroy(&dice->stream); + amdtp_stream_destroy(&dice->rx_stream); fw_core_remove_address_handler(&dice->notification_handler); mutex_destroy(&dice->mutex); } @@ -1217,7 +1217,7 @@ static int dice_interface_check(struct fw_unit *unit) return 0; } -static int highest_supported_mode_rate(struct dice *dice, unsigned int mode) +static int highest_supported_mode_rate(struct snd_dice *dice, unsigned int mode) { int i; @@ -1229,7 +1229,7 @@ static int highest_supported_mode_rate(struct dice *dice, unsigned int mode) return -1; } -static int dice_read_mode_params(struct dice *dice, unsigned int mode) +static int dice_read_mode_params(struct snd_dice *dice, unsigned int mode) { __be32 values[2]; int rate_index, err; @@ -1257,7 +1257,7 @@ static int dice_read_mode_params(struct dice *dice, unsigned int mode) return 0; } -static int dice_read_params(struct dice *dice) +static int dice_read_params(struct snd_dice *dice) { __be32 pointers[6]; __be32 value; @@ -1298,7 +1298,7 @@ static int dice_read_params(struct dice *dice) return 0; } -static void dice_card_strings(struct dice *dice) +static void dice_card_strings(struct snd_dice *dice) { struct snd_card *card = dice->card; struct fw_device *dev = fw_parent_device(dice->unit); @@ -1336,7 +1336,7 @@ static void dice_card_strings(struct dice *dice) static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) { struct snd_card *card; - struct dice *dice; + struct snd_dice *dice; __be32 clock_sel; int err; @@ -1373,12 +1373,12 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) if (err < 0) goto err_owner; - err = fw_iso_resources_init(&dice->resources, unit); + err = fw_iso_resources_init(&dice->rx_resources, unit); if (err < 0) goto err_owner; - dice->resources.channels_mask = 0x00000000ffffffffuLL; + dice->rx_resources.channels_mask = 0x00000000ffffffffuLL; - err = amdtp_stream_init(&dice->stream, unit, AMDTP_OUT_STREAM, + err = amdtp_stream_init(&dice->rx_stream, unit, AMDTP_OUT_STREAM, CIP_BLOCKING); if (err < 0) goto err_resources; @@ -1419,7 +1419,7 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) return 0; err_resources: - fw_iso_resources_destroy(&dice->resources); + fw_iso_resources_destroy(&dice->rx_resources); err_owner: dice_owner_clear(dice); err_notification_handler: @@ -1433,9 +1433,9 @@ error: static void dice_remove(struct fw_unit *unit) { - struct dice *dice = dev_get_drvdata(&unit->device); + struct snd_dice *dice = dev_get_drvdata(&unit->device); - amdtp_stream_pcm_abort(&dice->stream); + amdtp_stream_pcm_abort(&dice->rx_stream); snd_card_disconnect(dice->card); @@ -1451,7 +1451,7 @@ static void dice_remove(struct fw_unit *unit) static void dice_bus_reset(struct fw_unit *unit) { - struct dice *dice = dev_get_drvdata(&unit->device); + struct snd_dice *dice = dev_get_drvdata(&unit->device); /* * On a bus reset, the DICE firmware disables streaming and then goes @@ -1461,7 +1461,7 @@ static void dice_bus_reset(struct fw_unit *unit) * to stop so that the application can restart them in an orderly * manner. */ - amdtp_stream_pcm_abort(&dice->stream); + amdtp_stream_pcm_abort(&dice->rx_stream); mutex_lock(&dice->mutex); @@ -1470,7 +1470,7 @@ static void dice_bus_reset(struct fw_unit *unit) dice_owner_update(dice); - fw_iso_resources_update(&dice->resources); + fw_iso_resources_update(&dice->rx_resources); mutex_unlock(&dice->mutex); } -- cgit v1.2.3 From 14ff6a094815988b018ea4d698c2e2cc3ceee27c Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sat, 29 Nov 2014 00:59:12 +0900 Subject: ALSA: dice: Move file to its own directory In followed commits, dice driver is split into several files. For easily managing these files, this commit adds subdirectory and move file into the directory. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/Makefile | 3 +- sound/firewire/dice-interface.h | 371 --------- sound/firewire/dice.c | 1512 ---------------------------------- sound/firewire/dice/Makefile | 2 + sound/firewire/dice/dice-interface.h | 371 +++++++++ sound/firewire/dice/dice.c | 1512 ++++++++++++++++++++++++++++++++++ 6 files changed, 1886 insertions(+), 1885 deletions(-) delete mode 100644 sound/firewire/dice-interface.h delete mode 100644 sound/firewire/dice.c create mode 100644 sound/firewire/dice/Makefile create mode 100644 sound/firewire/dice/dice-interface.h create mode 100644 sound/firewire/dice/dice.c (limited to 'sound') diff --git a/sound/firewire/Makefile b/sound/firewire/Makefile index fad8d49306ab..c50761ccd66a 100644 --- a/sound/firewire/Makefile +++ b/sound/firewire/Makefile @@ -1,12 +1,11 @@ snd-firewire-lib-objs := lib.o iso-resources.o packets-buffer.o \ fcp.o cmp.o amdtp.o -snd-dice-objs := dice.o snd-firewire-speakers-objs := speakers.o snd-isight-objs := isight.o snd-scs1x-objs := scs1x.o obj-$(CONFIG_SND_FIREWIRE_LIB) += snd-firewire-lib.o -obj-$(CONFIG_SND_DICE) += snd-dice.o +obj-$(CONFIG_SND_DICE) += dice/ obj-$(CONFIG_SND_FIREWIRE_SPEAKERS) += snd-firewire-speakers.o obj-$(CONFIG_SND_ISIGHT) += snd-isight.o obj-$(CONFIG_SND_SCS1X) += snd-scs1x.o diff --git a/sound/firewire/dice-interface.h b/sound/firewire/dice-interface.h deleted file mode 100644 index 27b044f84c81..000000000000 --- a/sound/firewire/dice-interface.h +++ /dev/null @@ -1,371 +0,0 @@ -#ifndef SOUND_FIREWIRE_DICE_INTERFACE_H_INCLUDED -#define SOUND_FIREWIRE_DICE_INTERFACE_H_INCLUDED - -/* - * DICE device interface definitions - */ - -/* - * Generally, all registers can be read like memory, i.e., with quadlet read or - * block read transactions with at least quadlet-aligned offset and length. - * Writes are not allowed except where noted; quadlet-sized registers must be - * written with a quadlet write transaction. - * - * All values are in big endian. The DICE firmware runs on a little-endian CPU - * and just byte-swaps _all_ quadlets on the bus, so values without endianness - * (e.g. strings) get scrambled and must be byte-swapped again by the driver. - */ - -/* - * Streaming is handled by the "DICE driver" interface. Its registers are - * located in this private address space. - */ -#define DICE_PRIVATE_SPACE 0xffffe0000000uLL - -/* - * The registers are organized in several sections, which are organized - * separately to allow them to be extended individually. Whether a register is - * supported can be detected by checking its offset against its section's size. - * - * The section offset values are relative to DICE_PRIVATE_SPACE; the offset/ - * size values are measured in quadlets. Read-only. - */ -#define DICE_GLOBAL_OFFSET 0x00 -#define DICE_GLOBAL_SIZE 0x04 -#define DICE_TX_OFFSET 0x08 -#define DICE_TX_SIZE 0x0c -#define DICE_RX_OFFSET 0x10 -#define DICE_RX_SIZE 0x14 -#define DICE_EXT_SYNC_OFFSET 0x18 -#define DICE_EXT_SYNC_SIZE 0x1c -#define DICE_UNUSED2_OFFSET 0x20 -#define DICE_UNUSED2_SIZE 0x24 - -/* - * Global settings. - */ - -/* - * Stores the full 64-bit address (node ID and offset in the node's address - * space) where the device will send notifications. Must be changed with - * a compare/swap transaction by the owner. This register is automatically - * cleared on a bus reset. - */ -#define GLOBAL_OWNER 0x000 -#define OWNER_NO_OWNER 0xffff000000000000uLL -#define OWNER_NODE_SHIFT 48 - -/* - * A bitmask with asynchronous events; read-only. When any event(s) happen, - * the bits of previous events are cleared, and the value of this register is - * also written to the address stored in the owner register. - */ -#define GLOBAL_NOTIFICATION 0x008 -/* Some registers in the Rx/Tx sections may have changed. */ -#define NOTIFY_RX_CFG_CHG 0x00000001 -#define NOTIFY_TX_CFG_CHG 0x00000002 -/* Lock status of the current clock source may have changed. */ -#define NOTIFY_LOCK_CHG 0x00000010 -/* Write to the clock select register has been finished. */ -#define NOTIFY_CLOCK_ACCEPTED 0x00000020 -/* Lock status of some clock source has changed. */ -#define NOTIFY_EXT_STATUS 0x00000040 -/* Other bits may be used for device-specific events. */ - -/* - * A name that can be customized for each device; read/write. Padded with zero - * bytes. Quadlets are byte-swapped. The encoding is whatever the host driver - * happens to be using. - */ -#define GLOBAL_NICK_NAME 0x00c -#define NICK_NAME_SIZE 64 - -/* - * The current sample rate and clock source; read/write. Whether a clock - * source or sample rate is supported is device-specific; the internal clock - * source is always available. Low/mid/high = up to 48/96/192 kHz. This - * register can be changed even while streams are running. - */ -#define GLOBAL_CLOCK_SELECT 0x04c -#define CLOCK_SOURCE_MASK 0x000000ff -#define CLOCK_SOURCE_AES1 0x00000000 -#define CLOCK_SOURCE_AES2 0x00000001 -#define CLOCK_SOURCE_AES3 0x00000002 -#define CLOCK_SOURCE_AES4 0x00000003 -#define CLOCK_SOURCE_AES_ANY 0x00000004 -#define CLOCK_SOURCE_ADAT 0x00000005 -#define CLOCK_SOURCE_TDIF 0x00000006 -#define CLOCK_SOURCE_WC 0x00000007 -#define CLOCK_SOURCE_ARX1 0x00000008 -#define CLOCK_SOURCE_ARX2 0x00000009 -#define CLOCK_SOURCE_ARX3 0x0000000a -#define CLOCK_SOURCE_ARX4 0x0000000b -#define CLOCK_SOURCE_INTERNAL 0x0000000c -#define CLOCK_RATE_MASK 0x0000ff00 -#define CLOCK_RATE_32000 0x00000000 -#define CLOCK_RATE_44100 0x00000100 -#define CLOCK_RATE_48000 0x00000200 -#define CLOCK_RATE_88200 0x00000300 -#define CLOCK_RATE_96000 0x00000400 -#define CLOCK_RATE_176400 0x00000500 -#define CLOCK_RATE_192000 0x00000600 -#define CLOCK_RATE_ANY_LOW 0x00000700 -#define CLOCK_RATE_ANY_MID 0x00000800 -#define CLOCK_RATE_ANY_HIGH 0x00000900 -#define CLOCK_RATE_NONE 0x00000a00 -#define CLOCK_RATE_SHIFT 8 - -/* - * Enable streaming; read/write. Writing a non-zero value (re)starts all - * streams that have a valid iso channel set; zero stops all streams. The - * streams' parameters must be configured before starting. This register is - * automatically cleared on a bus reset. - */ -#define GLOBAL_ENABLE 0x050 - -/* - * Status of the sample clock; read-only. - */ -#define GLOBAL_STATUS 0x054 -/* The current clock source is locked. */ -#define STATUS_SOURCE_LOCKED 0x00000001 -/* The actual sample rate; CLOCK_RATE_32000-_192000 or _NONE. */ -#define STATUS_NOMINAL_RATE_MASK 0x0000ff00 - -/* - * Status of all clock sources; read-only. - */ -#define GLOBAL_EXTENDED_STATUS 0x058 -/* - * The _LOCKED bits always show the current status; any change generates - * a notification. - */ -#define EXT_STATUS_AES1_LOCKED 0x00000001 -#define EXT_STATUS_AES2_LOCKED 0x00000002 -#define EXT_STATUS_AES3_LOCKED 0x00000004 -#define EXT_STATUS_AES4_LOCKED 0x00000008 -#define EXT_STATUS_ADAT_LOCKED 0x00000010 -#define EXT_STATUS_TDIF_LOCKED 0x00000020 -#define EXT_STATUS_ARX1_LOCKED 0x00000040 -#define EXT_STATUS_ARX2_LOCKED 0x00000080 -#define EXT_STATUS_ARX3_LOCKED 0x00000100 -#define EXT_STATUS_ARX4_LOCKED 0x00000200 -#define EXT_STATUS_WC_LOCKED 0x00000400 -/* - * The _SLIP bits do not generate notifications; a set bit indicates that an - * error occurred since the last time when this register was read with - * a quadlet read transaction. - */ -#define EXT_STATUS_AES1_SLIP 0x00010000 -#define EXT_STATUS_AES2_SLIP 0x00020000 -#define EXT_STATUS_AES3_SLIP 0x00040000 -#define EXT_STATUS_AES4_SLIP 0x00080000 -#define EXT_STATUS_ADAT_SLIP 0x00100000 -#define EXT_STATUS_TDIF_SLIP 0x00200000 -#define EXT_STATUS_ARX1_SLIP 0x00400000 -#define EXT_STATUS_ARX2_SLIP 0x00800000 -#define EXT_STATUS_ARX3_SLIP 0x01000000 -#define EXT_STATUS_ARX4_SLIP 0x02000000 -#define EXT_STATUS_WC_SLIP 0x04000000 - -/* - * The measured rate of the current clock source, in Hz; read-only. - */ -#define GLOBAL_SAMPLE_RATE 0x05c - -/* - * The version of the DICE driver specification that this device conforms to; - * read-only. - */ -#define GLOBAL_VERSION 0x060 - -/* Some old firmware versions do not have the following global registers: */ - -/* - * Supported sample rates and clock sources; read-only. - */ -#define GLOBAL_CLOCK_CAPABILITIES 0x064 -#define CLOCK_CAP_RATE_32000 0x00000001 -#define CLOCK_CAP_RATE_44100 0x00000002 -#define CLOCK_CAP_RATE_48000 0x00000004 -#define CLOCK_CAP_RATE_88200 0x00000008 -#define CLOCK_CAP_RATE_96000 0x00000010 -#define CLOCK_CAP_RATE_176400 0x00000020 -#define CLOCK_CAP_RATE_192000 0x00000040 -#define CLOCK_CAP_SOURCE_AES1 0x00010000 -#define CLOCK_CAP_SOURCE_AES2 0x00020000 -#define CLOCK_CAP_SOURCE_AES3 0x00040000 -#define CLOCK_CAP_SOURCE_AES4 0x00080000 -#define CLOCK_CAP_SOURCE_AES_ANY 0x00100000 -#define CLOCK_CAP_SOURCE_ADAT 0x00200000 -#define CLOCK_CAP_SOURCE_TDIF 0x00400000 -#define CLOCK_CAP_SOURCE_WC 0x00800000 -#define CLOCK_CAP_SOURCE_ARX1 0x01000000 -#define CLOCK_CAP_SOURCE_ARX2 0x02000000 -#define CLOCK_CAP_SOURCE_ARX3 0x04000000 -#define CLOCK_CAP_SOURCE_ARX4 0x08000000 -#define CLOCK_CAP_SOURCE_INTERNAL 0x10000000 - -/* - * Names of all clock sources; read-only. Quadlets are byte-swapped. Names - * are separated with one backslash, the list is terminated with two - * backslashes. Unused clock sources are included. - */ -#define GLOBAL_CLOCK_SOURCE_NAMES 0x068 -#define CLOCK_SOURCE_NAMES_SIZE 256 - -/* - * Capture stream settings. This section includes the number/size registers - * and the registers of all streams. - */ - -/* - * The number of supported capture streams; read-only. - */ -#define TX_NUMBER 0x000 - -/* - * The size of one stream's register block, in quadlets; read-only. The - * registers of the first stream follow immediately afterwards; the registers - * of the following streams are offset by this register's value. - */ -#define TX_SIZE 0x004 - -/* - * The isochronous channel number on which packets are sent, or -1 if the - * stream is not to be used; read/write. - */ -#define TX_ISOCHRONOUS 0x008 - -/* - * The number of audio channels; read-only. There will be one quadlet per - * channel; the first channel is the first quadlet in a data block. - */ -#define TX_NUMBER_AUDIO 0x00c - -/* - * The number of MIDI ports, 0-8; read-only. If > 0, there will be one - * additional quadlet in each data block, following the audio quadlets. - */ -#define TX_NUMBER_MIDI 0x010 - -/* - * The speed at which the packets are sent, SCODE_100-_400; read/write. - */ -#define TX_SPEED 0x014 - -/* - * Names of all audio channels; read-only. Quadlets are byte-swapped. Names - * are separated with one backslash, the list is terminated with two - * backslashes. - */ -#define TX_NAMES 0x018 -#define TX_NAMES_SIZE 256 - -/* - * Audio IEC60958 capabilities; read-only. Bitmask with one bit per audio - * channel. - */ -#define TX_AC3_CAPABILITIES 0x118 - -/* - * Send audio data with IEC60958 label; read/write. Bitmask with one bit per - * audio channel. This register can be changed even while the stream is - * running. - */ -#define TX_AC3_ENABLE 0x11c - -/* - * Playback stream settings. This section includes the number/size registers - * and the registers of all streams. - */ - -/* - * The number of supported playback streams; read-only. - */ -#define RX_NUMBER 0x000 - -/* - * The size of one stream's register block, in quadlets; read-only. The - * registers of the first stream follow immediately afterwards; the registers - * of the following streams are offset by this register's value. - */ -#define RX_SIZE 0x004 - -/* - * The isochronous channel number on which packets are received, or -1 if the - * stream is not to be used; read/write. - */ -#define RX_ISOCHRONOUS 0x008 - -/* - * Index of first quadlet to be interpreted; read/write. If > 0, that many - * quadlets at the beginning of each data block will be ignored, and all the - * audio and MIDI quadlets will follow. - */ -#define RX_SEQ_START 0x00c - -/* - * The number of audio channels; read-only. There will be one quadlet per - * channel. - */ -#define RX_NUMBER_AUDIO 0x010 - -/* - * The number of MIDI ports, 0-8; read-only. If > 0, there will be one - * additional quadlet in each data block, following the audio quadlets. - */ -#define RX_NUMBER_MIDI 0x014 - -/* - * Names of all audio channels; read-only. Quadlets are byte-swapped. Names - * are separated with one backslash, the list is terminated with two - * backslashes. - */ -#define RX_NAMES 0x018 -#define RX_NAMES_SIZE 256 - -/* - * Audio IEC60958 capabilities; read-only. Bitmask with one bit per audio - * channel. - */ -#define RX_AC3_CAPABILITIES 0x118 - -/* - * Receive audio data with IEC60958 label; read/write. Bitmask with one bit - * per audio channel. This register can be changed even while the stream is - * running. - */ -#define RX_AC3_ENABLE 0x11c - -/* - * Extended synchronization information. - * This section can be read completely with a block read request. - */ - -/* - * Current clock source; read-only. - */ -#define EXT_SYNC_CLOCK_SOURCE 0x000 - -/* - * Clock source is locked (boolean); read-only. - */ -#define EXT_SYNC_LOCKED 0x004 - -/* - * Current sample rate (CLOCK_RATE_* >> CLOCK_RATE_SHIFT), _32000-_192000 or - * _NONE; read-only. - */ -#define EXT_SYNC_RATE 0x008 - -/* - * ADAT user data bits; read-only. - */ -#define EXT_SYNC_ADAT_USER_DATA 0x00c -/* The data bits, if available. */ -#define ADAT_USER_DATA_MASK 0x0f -/* The data bits are not available. */ -#define ADAT_USER_DATA_NO_DATA 0x10 - -#endif diff --git a/sound/firewire/dice.c b/sound/firewire/dice.c deleted file mode 100644 index eafd74b97376..000000000000 --- a/sound/firewire/dice.c +++ /dev/null @@ -1,1512 +0,0 @@ -/* - * TC Applied Technologies Digital Interface Communications Engine driver - * - * Copyright (c) Clemens Ladisch - * Licensed under the terms of the GNU General Public License, version 2. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "amdtp.h" -#include "iso-resources.h" -#include "lib.h" -#include "dice-interface.h" - - -struct snd_dice { - struct snd_card *card; - struct fw_unit *unit; - spinlock_t lock; - struct mutex mutex; - unsigned int global_offset; - unsigned int rx_offset; - unsigned int clock_caps; - unsigned int rx_channels[3]; - unsigned int rx_midi_ports[3]; - struct fw_address_handler notification_handler; - int owner_generation; - int dev_lock_count; /* > 0 driver, < 0 userspace */ - bool dev_lock_changed; - bool global_enabled; - struct completion clock_accepted; - wait_queue_head_t hwdep_wait; - u32 notification_bits; - struct fw_iso_resources rx_resources; - struct amdtp_stream rx_stream; -}; - -MODULE_DESCRIPTION("DICE driver"); -MODULE_AUTHOR("Clemens Ladisch "); -MODULE_LICENSE("GPL v2"); - -static const unsigned int dice_rates[] = { - /* mode 0 */ - [0] = 32000, - [1] = 44100, - [2] = 48000, - /* mode 1 */ - [3] = 88200, - [4] = 96000, - /* mode 2 */ - [5] = 176400, - [6] = 192000, -}; - -static unsigned int rate_to_index(unsigned int rate) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(dice_rates); ++i) - if (dice_rates[i] == rate) - return i; - - return 0; -} - -static unsigned int rate_index_to_mode(unsigned int rate_index) -{ - return ((int)rate_index - 1) / 2; -} - -static void dice_lock_changed(struct snd_dice *dice) -{ - dice->dev_lock_changed = true; - wake_up(&dice->hwdep_wait); -} - -static int dice_try_lock(struct snd_dice *dice) -{ - int err; - - spin_lock_irq(&dice->lock); - - if (dice->dev_lock_count < 0) { - err = -EBUSY; - goto out; - } - - if (dice->dev_lock_count++ == 0) - dice_lock_changed(dice); - err = 0; - -out: - spin_unlock_irq(&dice->lock); - - return err; -} - -static void dice_unlock(struct snd_dice *dice) -{ - spin_lock_irq(&dice->lock); - - if (WARN_ON(dice->dev_lock_count <= 0)) - goto out; - - if (--dice->dev_lock_count == 0) - dice_lock_changed(dice); - -out: - spin_unlock_irq(&dice->lock); -} - -static inline u64 global_address(struct snd_dice *dice, unsigned int offset) -{ - return DICE_PRIVATE_SPACE + dice->global_offset + offset; -} - -/* TODO: rx index */ -static inline u64 rx_address(struct snd_dice *dice, unsigned int offset) -{ - return DICE_PRIVATE_SPACE + dice->rx_offset + offset; -} - -static int dice_owner_set(struct snd_dice *dice) -{ - struct fw_device *device = fw_parent_device(dice->unit); - __be64 *buffer; - int err, errors = 0; - - buffer = kmalloc(2 * 8, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - for (;;) { - buffer[0] = cpu_to_be64(OWNER_NO_OWNER); - buffer[1] = cpu_to_be64( - ((u64)device->card->node_id << OWNER_NODE_SHIFT) | - dice->notification_handler.offset); - - dice->owner_generation = device->generation; - smp_rmb(); /* node_id vs. generation */ - err = snd_fw_transaction(dice->unit, - TCODE_LOCK_COMPARE_SWAP, - global_address(dice, GLOBAL_OWNER), - buffer, 2 * 8, - FW_FIXED_GENERATION | - dice->owner_generation); - - if (err == 0) { - if (buffer[0] != cpu_to_be64(OWNER_NO_OWNER)) { - dev_err(&dice->unit->device, - "device is already in use\n"); - err = -EBUSY; - } - break; - } - if (err != -EAGAIN || ++errors >= 3) - break; - - msleep(20); - } - - kfree(buffer); - - return err; -} - -static int dice_owner_update(struct snd_dice *dice) -{ - struct fw_device *device = fw_parent_device(dice->unit); - __be64 *buffer; - int err; - - if (dice->owner_generation == -1) - return 0; - - buffer = kmalloc(2 * 8, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - buffer[0] = cpu_to_be64(OWNER_NO_OWNER); - buffer[1] = cpu_to_be64( - ((u64)device->card->node_id << OWNER_NODE_SHIFT) | - dice->notification_handler.offset); - - dice->owner_generation = device->generation; - smp_rmb(); /* node_id vs. generation */ - err = snd_fw_transaction(dice->unit, TCODE_LOCK_COMPARE_SWAP, - global_address(dice, GLOBAL_OWNER), - buffer, 2 * 8, - FW_FIXED_GENERATION | dice->owner_generation); - - if (err == 0) { - if (buffer[0] != cpu_to_be64(OWNER_NO_OWNER)) { - dev_err(&dice->unit->device, - "device is already in use\n"); - err = -EBUSY; - } - } else if (err == -EAGAIN) { - err = 0; /* try again later */ - } - - kfree(buffer); - - if (err < 0) - dice->owner_generation = -1; - - return err; -} - -static void dice_owner_clear(struct snd_dice *dice) -{ - struct fw_device *device = fw_parent_device(dice->unit); - __be64 *buffer; - - buffer = kmalloc(2 * 8, GFP_KERNEL); - if (!buffer) - return; - - buffer[0] = cpu_to_be64( - ((u64)device->card->node_id << OWNER_NODE_SHIFT) | - dice->notification_handler.offset); - buffer[1] = cpu_to_be64(OWNER_NO_OWNER); - snd_fw_transaction(dice->unit, TCODE_LOCK_COMPARE_SWAP, - global_address(dice, GLOBAL_OWNER), - buffer, 2 * 8, FW_QUIET | - FW_FIXED_GENERATION | dice->owner_generation); - - kfree(buffer); - - dice->owner_generation = -1; -} - -static int dice_enable_set(struct snd_dice *dice) -{ - __be32 value; - int err; - - value = cpu_to_be32(1); - err = snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST, - global_address(dice, GLOBAL_ENABLE), - &value, 4, - FW_FIXED_GENERATION | dice->owner_generation); - if (err < 0) - return err; - - dice->global_enabled = true; - - return 0; -} - -static void dice_enable_clear(struct snd_dice *dice) -{ - __be32 value; - - if (!dice->global_enabled) - return; - - value = 0; - snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST, - global_address(dice, GLOBAL_ENABLE), - &value, 4, FW_QUIET | - FW_FIXED_GENERATION | dice->owner_generation); - - dice->global_enabled = false; -} - -static void dice_notification(struct fw_card *card, struct fw_request *request, - int tcode, int destination, int source, - int generation, unsigned long long offset, - void *data, size_t length, void *callback_data) -{ - struct snd_dice *dice = callback_data; - u32 bits; - unsigned long flags; - - if (tcode != TCODE_WRITE_QUADLET_REQUEST) { - fw_send_response(card, request, RCODE_TYPE_ERROR); - return; - } - if ((offset & 3) != 0) { - fw_send_response(card, request, RCODE_ADDRESS_ERROR); - return; - } - - bits = be32_to_cpup(data); - - spin_lock_irqsave(&dice->lock, flags); - dice->notification_bits |= bits; - spin_unlock_irqrestore(&dice->lock, flags); - - fw_send_response(card, request, RCODE_COMPLETE); - - if (bits & NOTIFY_CLOCK_ACCEPTED) - complete(&dice->clock_accepted); - wake_up(&dice->hwdep_wait); -} - -static int dice_rate_constraint(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - struct snd_dice *dice = rule->private; - const struct snd_interval *channels = - hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_interval *rate = - hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval allowed_rates = { - .min = UINT_MAX, .max = 0, .integer = 1 - }; - unsigned int i, mode; - - for (i = 0; i < ARRAY_SIZE(dice_rates); ++i) { - mode = rate_index_to_mode(i); - if ((dice->clock_caps & (1 << i)) && - snd_interval_test(channels, dice->rx_channels[mode])) { - allowed_rates.min = min(allowed_rates.min, - dice_rates[i]); - allowed_rates.max = max(allowed_rates.max, - dice_rates[i]); - } - } - - return snd_interval_refine(rate, &allowed_rates); -} - -static int dice_channels_constraint(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - struct snd_dice *dice = rule->private; - const struct snd_interval *rate = - hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *channels = - hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_interval allowed_channels = { - .min = UINT_MAX, .max = 0, .integer = 1 - }; - unsigned int i, mode; - - for (i = 0; i < ARRAY_SIZE(dice_rates); ++i) - if ((dice->clock_caps & (1 << i)) && - snd_interval_test(rate, dice_rates[i])) { - mode = rate_index_to_mode(i); - allowed_channels.min = min(allowed_channels.min, - dice->rx_channels[mode]); - allowed_channels.max = max(allowed_channels.max, - dice->rx_channels[mode]); - } - - return snd_interval_refine(channels, &allowed_channels); -} - -static int dice_open(struct snd_pcm_substream *substream) -{ - static const struct snd_pcm_hardware hardware = { - .info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_BATCH | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER, - .formats = AMDTP_OUT_PCM_FORMAT_BITS, - .channels_min = UINT_MAX, - .channels_max = 0, - .buffer_bytes_max = 16 * 1024 * 1024, - .period_bytes_min = 1, - .period_bytes_max = UINT_MAX, - .periods_min = 1, - .periods_max = UINT_MAX, - }; - struct snd_dice *dice = substream->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; - unsigned int i; - int err; - - err = dice_try_lock(dice); - if (err < 0) - goto error; - - runtime->hw = hardware; - - for (i = 0; i < ARRAY_SIZE(dice_rates); ++i) - if (dice->clock_caps & (1 << i)) - runtime->hw.rates |= - snd_pcm_rate_to_rate_bit(dice_rates[i]); - snd_pcm_limit_hw_rates(runtime); - - for (i = 0; i < 3; ++i) - if (dice->rx_channels[i]) { - runtime->hw.channels_min = min(runtime->hw.channels_min, - dice->rx_channels[i]); - runtime->hw.channels_max = max(runtime->hw.channels_max, - dice->rx_channels[i]); - } - - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - dice_rate_constraint, dice, - SNDRV_PCM_HW_PARAM_CHANNELS, -1); - if (err < 0) - goto err_lock; - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - dice_channels_constraint, dice, - SNDRV_PCM_HW_PARAM_RATE, -1); - if (err < 0) - goto err_lock; - - err = amdtp_stream_add_pcm_hw_constraints(&dice->rx_stream, runtime); - if (err < 0) - goto err_lock; - - return 0; - -err_lock: - dice_unlock(dice); -error: - return err; -} - -static int dice_close(struct snd_pcm_substream *substream) -{ - struct snd_dice *dice = substream->private_data; - - dice_unlock(dice); - - return 0; -} - -static int dice_stream_start_packets(struct snd_dice *dice) -{ - int err; - - if (amdtp_stream_running(&dice->rx_stream)) - return 0; - - err = amdtp_stream_start(&dice->rx_stream, dice->rx_resources.channel, - fw_parent_device(dice->unit)->max_speed); - if (err < 0) - return err; - - err = dice_enable_set(dice); - if (err < 0) { - amdtp_stream_stop(&dice->rx_stream); - return err; - } - - return 0; -} - -static int dice_stream_start(struct snd_dice *dice) -{ - __be32 channel; - int err; - - if (!dice->rx_resources.allocated) { - err = fw_iso_resources_allocate(&dice->rx_resources, - amdtp_stream_get_max_payload(&dice->rx_stream), - fw_parent_device(dice->unit)->max_speed); - if (err < 0) - goto error; - - channel = cpu_to_be32(dice->rx_resources.channel); - err = snd_fw_transaction(dice->unit, - TCODE_WRITE_QUADLET_REQUEST, - rx_address(dice, RX_ISOCHRONOUS), - &channel, 4, 0); - if (err < 0) - goto err_resources; - } - - err = dice_stream_start_packets(dice); - if (err < 0) - goto err_rx_channel; - - return 0; - -err_rx_channel: - channel = cpu_to_be32((u32)-1); - snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST, - rx_address(dice, RX_ISOCHRONOUS), &channel, 4, 0); -err_resources: - fw_iso_resources_free(&dice->rx_resources); -error: - return err; -} - -static void dice_stream_stop_packets(struct snd_dice *dice) -{ - if (amdtp_stream_running(&dice->rx_stream)) { - dice_enable_clear(dice); - amdtp_stream_stop(&dice->rx_stream); - } -} - -static void dice_stream_stop(struct snd_dice *dice) -{ - __be32 channel; - - dice_stream_stop_packets(dice); - - if (!dice->rx_resources.allocated) - return; - - channel = cpu_to_be32((u32)-1); - snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST, - rx_address(dice, RX_ISOCHRONOUS), &channel, 4, 0); - - fw_iso_resources_free(&dice->rx_resources); -} - -static int dice_change_rate(struct snd_dice *dice, unsigned int clock_rate) -{ - __be32 value; - int err; - - reinit_completion(&dice->clock_accepted); - - value = cpu_to_be32(clock_rate | CLOCK_SOURCE_ARX1); - err = snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST, - global_address(dice, GLOBAL_CLOCK_SELECT), - &value, 4, 0); - if (err < 0) - return err; - - if (!wait_for_completion_timeout(&dice->clock_accepted, - msecs_to_jiffies(100))) - dev_warn(&dice->unit->device, "clock change timed out\n"); - - return 0; -} - -static int dice_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct snd_dice *dice = substream->private_data; - unsigned int rate_index, mode, rate, channels, i; - int err; - - mutex_lock(&dice->mutex); - dice_stream_stop(dice); - mutex_unlock(&dice->mutex); - - err = snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); - if (err < 0) - return err; - - rate = params_rate(hw_params); - rate_index = rate_to_index(rate); - err = dice_change_rate(dice, rate_index << CLOCK_RATE_SHIFT); - if (err < 0) - return err; - - /* - * At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in - * one data block of AMDTP packet. Thus sampling transfer frequency is - * a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are - * transferred on AMDTP packets at 96 kHz. Two successive samples of a - * channel are stored consecutively in the packet. This quirk is called - * as 'Dual Wire'. - * For this quirk, blocking mode is required and PCM buffer size should - * be aligned to SYT_INTERVAL. - */ - channels = params_channels(hw_params); - if (rate_index > 4) { - if (channels > AMDTP_MAX_CHANNELS_FOR_PCM / 2) { - err = -ENOSYS; - return err; - } - - rate /= 2; - channels *= 2; - dice->rx_stream.double_pcm_frames = true; - } else { - dice->rx_stream.double_pcm_frames = false; - } - - mode = rate_index_to_mode(rate_index); - amdtp_stream_set_parameters(&dice->rx_stream, rate, channels, - dice->rx_midi_ports[mode]); - if (rate_index > 4) { - channels /= 2; - - for (i = 0; i < channels; i++) { - dice->rx_stream.pcm_positions[i] = i * 2; - dice->rx_stream.pcm_positions[i + channels] = i * 2 + 1; - } - } - - amdtp_stream_set_pcm_format(&dice->rx_stream, - params_format(hw_params)); - - return 0; -} - -static int dice_hw_free(struct snd_pcm_substream *substream) -{ - struct snd_dice *dice = substream->private_data; - - mutex_lock(&dice->mutex); - dice_stream_stop(dice); - mutex_unlock(&dice->mutex); - - return snd_pcm_lib_free_vmalloc_buffer(substream); -} - -static int dice_prepare(struct snd_pcm_substream *substream) -{ - struct snd_dice *dice = substream->private_data; - int err; - - mutex_lock(&dice->mutex); - - if (amdtp_streaming_error(&dice->rx_stream)) - dice_stream_stop_packets(dice); - - err = dice_stream_start(dice); - if (err < 0) { - mutex_unlock(&dice->mutex); - return err; - } - - mutex_unlock(&dice->mutex); - - amdtp_stream_pcm_prepare(&dice->rx_stream); - - return 0; -} - -static int dice_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct snd_dice *dice = substream->private_data; - struct snd_pcm_substream *pcm; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - pcm = substream; - break; - case SNDRV_PCM_TRIGGER_STOP: - pcm = NULL; - break; - default: - return -EINVAL; - } - amdtp_stream_pcm_trigger(&dice->rx_stream, pcm); - - return 0; -} - -static snd_pcm_uframes_t dice_pointer(struct snd_pcm_substream *substream) -{ - struct snd_dice *dice = substream->private_data; - - return amdtp_stream_pcm_pointer(&dice->rx_stream); -} - -static int dice_create_pcm(struct snd_dice *dice) -{ - static struct snd_pcm_ops ops = { - .open = dice_open, - .close = dice_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = dice_hw_params, - .hw_free = dice_hw_free, - .prepare = dice_prepare, - .trigger = dice_trigger, - .pointer = dice_pointer, - .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, - }; - struct snd_pcm *pcm; - int err; - - err = snd_pcm_new(dice->card, "DICE", 0, 1, 0, &pcm); - if (err < 0) - return err; - pcm->private_data = dice; - strcpy(pcm->name, dice->card->shortname); - pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->ops = &ops; - - return 0; -} - -static long dice_hwdep_read(struct snd_hwdep *hwdep, char __user *buf, - long count, loff_t *offset) -{ - struct snd_dice *dice = hwdep->private_data; - DEFINE_WAIT(wait); - union snd_firewire_event event; - - spin_lock_irq(&dice->lock); - - while (!dice->dev_lock_changed && dice->notification_bits == 0) { - prepare_to_wait(&dice->hwdep_wait, &wait, TASK_INTERRUPTIBLE); - spin_unlock_irq(&dice->lock); - schedule(); - finish_wait(&dice->hwdep_wait, &wait); - if (signal_pending(current)) - return -ERESTARTSYS; - spin_lock_irq(&dice->lock); - } - - memset(&event, 0, sizeof(event)); - if (dice->dev_lock_changed) { - event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS; - event.lock_status.status = dice->dev_lock_count > 0; - dice->dev_lock_changed = false; - - count = min_t(long, count, sizeof(event.lock_status)); - } else { - event.dice_notification.type = - SNDRV_FIREWIRE_EVENT_DICE_NOTIFICATION; - event.dice_notification.notification = dice->notification_bits; - dice->notification_bits = 0; - - count = min_t(long, count, sizeof(event.dice_notification)); - } - - spin_unlock_irq(&dice->lock); - - if (copy_to_user(buf, &event, count)) - return -EFAULT; - - return count; -} - -static unsigned int dice_hwdep_poll(struct snd_hwdep *hwdep, struct file *file, - poll_table *wait) -{ - struct snd_dice *dice = hwdep->private_data; - unsigned int events; - - poll_wait(file, &dice->hwdep_wait, wait); - - spin_lock_irq(&dice->lock); - if (dice->dev_lock_changed || dice->notification_bits != 0) - events = POLLIN | POLLRDNORM; - else - events = 0; - spin_unlock_irq(&dice->lock); - - return events; -} - -static int dice_hwdep_get_info(struct snd_dice *dice, void __user *arg) -{ - struct fw_device *dev = fw_parent_device(dice->unit); - struct snd_firewire_get_info info; - - memset(&info, 0, sizeof(info)); - info.type = SNDRV_FIREWIRE_TYPE_DICE; - info.card = dev->card->index; - *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]); - *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]); - strlcpy(info.device_name, dev_name(&dev->device), - sizeof(info.device_name)); - - if (copy_to_user(arg, &info, sizeof(info))) - return -EFAULT; - - return 0; -} - -static int dice_hwdep_lock(struct snd_dice *dice) -{ - int err; - - spin_lock_irq(&dice->lock); - - if (dice->dev_lock_count == 0) { - dice->dev_lock_count = -1; - err = 0; - } else { - err = -EBUSY; - } - - spin_unlock_irq(&dice->lock); - - return err; -} - -static int dice_hwdep_unlock(struct snd_dice *dice) -{ - int err; - - spin_lock_irq(&dice->lock); - - if (dice->dev_lock_count == -1) { - dice->dev_lock_count = 0; - err = 0; - } else { - err = -EBADFD; - } - - spin_unlock_irq(&dice->lock); - - return err; -} - -static int dice_hwdep_release(struct snd_hwdep *hwdep, struct file *file) -{ - struct snd_dice *dice = hwdep->private_data; - - spin_lock_irq(&dice->lock); - if (dice->dev_lock_count == -1) - dice->dev_lock_count = 0; - spin_unlock_irq(&dice->lock); - - return 0; -} - -static int dice_hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct snd_dice *dice = hwdep->private_data; - - switch (cmd) { - case SNDRV_FIREWIRE_IOCTL_GET_INFO: - return dice_hwdep_get_info(dice, (void __user *)arg); - case SNDRV_FIREWIRE_IOCTL_LOCK: - return dice_hwdep_lock(dice); - case SNDRV_FIREWIRE_IOCTL_UNLOCK: - return dice_hwdep_unlock(dice); - default: - return -ENOIOCTLCMD; - } -} - -#ifdef CONFIG_COMPAT -static int dice_hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file, - unsigned int cmd, unsigned long arg) -{ - return dice_hwdep_ioctl(hwdep, file, cmd, - (unsigned long)compat_ptr(arg)); -} -#else -#define dice_hwdep_compat_ioctl NULL -#endif - -static int dice_create_hwdep(struct snd_dice *dice) -{ - static const struct snd_hwdep_ops ops = { - .read = dice_hwdep_read, - .release = dice_hwdep_release, - .poll = dice_hwdep_poll, - .ioctl = dice_hwdep_ioctl, - .ioctl_compat = dice_hwdep_compat_ioctl, - }; - struct snd_hwdep *hwdep; - int err; - - err = snd_hwdep_new(dice->card, "DICE", 0, &hwdep); - if (err < 0) - return err; - strcpy(hwdep->name, "DICE"); - hwdep->iface = SNDRV_HWDEP_IFACE_FW_DICE; - hwdep->ops = ops; - hwdep->private_data = dice; - hwdep->exclusive = true; - - return 0; -} - -static int dice_proc_read_mem(struct snd_dice *dice, void *buffer, - unsigned int offset_q, unsigned int quadlets) -{ - unsigned int i; - int err; - - err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST, - DICE_PRIVATE_SPACE + 4 * offset_q, - buffer, 4 * quadlets, 0); - if (err < 0) - return err; - - for (i = 0; i < quadlets; ++i) - be32_to_cpus(&((u32 *)buffer)[i]); - - return 0; -} - -static const char *str_from_array(const char *const strs[], unsigned int count, - unsigned int i) -{ - if (i < count) - return strs[i]; - - return "(unknown)"; -} - -static void dice_proc_fixup_string(char *s, unsigned int size) -{ - unsigned int i; - - for (i = 0; i < size; i += 4) - cpu_to_le32s((u32 *)(s + i)); - - for (i = 0; i < size - 2; ++i) { - if (s[i] == '\0') - return; - if (s[i] == '\\' && s[i + 1] == '\\') { - s[i + 2] = '\0'; - return; - } - } - s[size - 1] = '\0'; -} - -static void dice_proc_read(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) -{ - static const char *const section_names[5] = { - "global", "tx", "rx", "ext_sync", "unused2" - }; - static const char *const clock_sources[] = { - "aes1", "aes2", "aes3", "aes4", "aes", "adat", "tdif", - "wc", "arx1", "arx2", "arx3", "arx4", "internal" - }; - static const char *const rates[] = { - "32000", "44100", "48000", "88200", "96000", "176400", "192000", - "any low", "any mid", "any high", "none" - }; - struct snd_dice *dice = entry->private_data; - u32 sections[ARRAY_SIZE(section_names) * 2]; - struct { - u32 number; - u32 size; - } tx_rx_header; - union { - struct { - u32 owner_hi, owner_lo; - u32 notification; - char nick_name[NICK_NAME_SIZE]; - u32 clock_select; - u32 enable; - u32 status; - u32 extended_status; - u32 sample_rate; - u32 version; - u32 clock_caps; - char clock_source_names[CLOCK_SOURCE_NAMES_SIZE]; - } global; - struct { - u32 iso; - u32 number_audio; - u32 number_midi; - u32 speed; - char names[TX_NAMES_SIZE]; - u32 ac3_caps; - u32 ac3_enable; - } tx; - struct { - u32 iso; - u32 seq_start; - u32 number_audio; - u32 number_midi; - char names[RX_NAMES_SIZE]; - u32 ac3_caps; - u32 ac3_enable; - } rx; - struct { - u32 clock_source; - u32 locked; - u32 rate; - u32 adat_user_data; - } ext_sync; - } buf; - unsigned int quadlets, stream, i; - - if (dice_proc_read_mem(dice, sections, 0, ARRAY_SIZE(sections)) < 0) - return; - snd_iprintf(buffer, "sections:\n"); - for (i = 0; i < ARRAY_SIZE(section_names); ++i) - snd_iprintf(buffer, " %s: offset %u, size %u\n", - section_names[i], - sections[i * 2], sections[i * 2 + 1]); - - quadlets = min_t(u32, sections[1], sizeof(buf.global) / 4); - if (dice_proc_read_mem(dice, &buf.global, sections[0], quadlets) < 0) - return; - snd_iprintf(buffer, "global:\n"); - snd_iprintf(buffer, " owner: %04x:%04x%08x\n", - buf.global.owner_hi >> 16, - buf.global.owner_hi & 0xffff, buf.global.owner_lo); - snd_iprintf(buffer, " notification: %08x\n", buf.global.notification); - dice_proc_fixup_string(buf.global.nick_name, NICK_NAME_SIZE); - snd_iprintf(buffer, " nick name: %s\n", buf.global.nick_name); - snd_iprintf(buffer, " clock select: %s %s\n", - str_from_array(clock_sources, ARRAY_SIZE(clock_sources), - buf.global.clock_select & CLOCK_SOURCE_MASK), - str_from_array(rates, ARRAY_SIZE(rates), - (buf.global.clock_select & CLOCK_RATE_MASK) - >> CLOCK_RATE_SHIFT)); - snd_iprintf(buffer, " enable: %u\n", buf.global.enable); - snd_iprintf(buffer, " status: %slocked %s\n", - buf.global.status & STATUS_SOURCE_LOCKED ? "" : "un", - str_from_array(rates, ARRAY_SIZE(rates), - (buf.global.status & - STATUS_NOMINAL_RATE_MASK) - >> CLOCK_RATE_SHIFT)); - snd_iprintf(buffer, " ext status: %08x\n", buf.global.extended_status); - snd_iprintf(buffer, " sample rate: %u\n", buf.global.sample_rate); - snd_iprintf(buffer, " version: %u.%u.%u.%u\n", - (buf.global.version >> 24) & 0xff, - (buf.global.version >> 16) & 0xff, - (buf.global.version >> 8) & 0xff, - (buf.global.version >> 0) & 0xff); - if (quadlets >= 90) { - snd_iprintf(buffer, " clock caps:"); - for (i = 0; i <= 6; ++i) - if (buf.global.clock_caps & (1 << i)) - snd_iprintf(buffer, " %s", rates[i]); - for (i = 0; i <= 12; ++i) - if (buf.global.clock_caps & (1 << (16 + i))) - snd_iprintf(buffer, " %s", clock_sources[i]); - snd_iprintf(buffer, "\n"); - dice_proc_fixup_string(buf.global.clock_source_names, - CLOCK_SOURCE_NAMES_SIZE); - snd_iprintf(buffer, " clock source names: %s\n", - buf.global.clock_source_names); - } - - if (dice_proc_read_mem(dice, &tx_rx_header, sections[2], 2) < 0) - return; - quadlets = min_t(u32, tx_rx_header.size, sizeof(buf.tx) / 4); - for (stream = 0; stream < tx_rx_header.number; ++stream) { - if (dice_proc_read_mem(dice, &buf.tx, sections[2] + 2 + - stream * tx_rx_header.size, - quadlets) < 0) - break; - snd_iprintf(buffer, "tx %u:\n", stream); - snd_iprintf(buffer, " iso channel: %d\n", (int)buf.tx.iso); - snd_iprintf(buffer, " audio channels: %u\n", - buf.tx.number_audio); - snd_iprintf(buffer, " midi ports: %u\n", buf.tx.number_midi); - snd_iprintf(buffer, " speed: S%u\n", 100u << buf.tx.speed); - if (quadlets >= 68) { - dice_proc_fixup_string(buf.tx.names, TX_NAMES_SIZE); - snd_iprintf(buffer, " names: %s\n", buf.tx.names); - } - if (quadlets >= 70) { - snd_iprintf(buffer, " ac3 caps: %08x\n", - buf.tx.ac3_caps); - snd_iprintf(buffer, " ac3 enable: %08x\n", - buf.tx.ac3_enable); - } - } - - if (dice_proc_read_mem(dice, &tx_rx_header, sections[4], 2) < 0) - return; - quadlets = min_t(u32, tx_rx_header.size, sizeof(buf.rx) / 4); - for (stream = 0; stream < tx_rx_header.number; ++stream) { - if (dice_proc_read_mem(dice, &buf.rx, sections[4] + 2 + - stream * tx_rx_header.size, - quadlets) < 0) - break; - snd_iprintf(buffer, "rx %u:\n", stream); - snd_iprintf(buffer, " iso channel: %d\n", (int)buf.rx.iso); - snd_iprintf(buffer, " sequence start: %u\n", buf.rx.seq_start); - snd_iprintf(buffer, " audio channels: %u\n", - buf.rx.number_audio); - snd_iprintf(buffer, " midi ports: %u\n", buf.rx.number_midi); - if (quadlets >= 68) { - dice_proc_fixup_string(buf.rx.names, RX_NAMES_SIZE); - snd_iprintf(buffer, " names: %s\n", buf.rx.names); - } - if (quadlets >= 70) { - snd_iprintf(buffer, " ac3 caps: %08x\n", - buf.rx.ac3_caps); - snd_iprintf(buffer, " ac3 enable: %08x\n", - buf.rx.ac3_enable); - } - } - - quadlets = min_t(u32, sections[7], sizeof(buf.ext_sync) / 4); - if (quadlets >= 4) { - if (dice_proc_read_mem(dice, &buf.ext_sync, - sections[6], 4) < 0) - return; - snd_iprintf(buffer, "ext status:\n"); - snd_iprintf(buffer, " clock source: %s\n", - str_from_array(clock_sources, - ARRAY_SIZE(clock_sources), - buf.ext_sync.clock_source)); - snd_iprintf(buffer, " locked: %u\n", buf.ext_sync.locked); - snd_iprintf(buffer, " rate: %s\n", - str_from_array(rates, ARRAY_SIZE(rates), - buf.ext_sync.rate)); - snd_iprintf(buffer, " adat user data: "); - if (buf.ext_sync.adat_user_data & ADAT_USER_DATA_NO_DATA) - snd_iprintf(buffer, "-\n"); - else - snd_iprintf(buffer, "%x\n", - buf.ext_sync.adat_user_data); - } -} - -static void dice_create_proc(struct snd_dice *dice) -{ - struct snd_info_entry *entry; - - if (!snd_card_proc_new(dice->card, "dice", &entry)) - snd_info_set_text_ops(entry, dice, dice_proc_read); -} - -static void dice_card_free(struct snd_card *card) -{ - struct snd_dice *dice = card->private_data; - - amdtp_stream_destroy(&dice->rx_stream); - fw_core_remove_address_handler(&dice->notification_handler); - mutex_destroy(&dice->mutex); -} - -#define OUI_WEISS 0x001c6a - -#define DICE_CATEGORY_ID 0x04 -#define WEISS_CATEGORY_ID 0x00 - -static int dice_interface_check(struct fw_unit *unit) -{ - static const int min_values[10] = { - 10, 0x64 / 4, - 10, 0x18 / 4, - 10, 0x18 / 4, - 0, 0, - 0, 0, - }; - struct fw_device *device = fw_parent_device(unit); - struct fw_csr_iterator it; - int key, value, vendor = -1, model = -1, err; - unsigned int category, i; - __be32 pointers[ARRAY_SIZE(min_values)]; - __be32 tx_data[4]; - __be32 version; - - /* - * Check that GUID and unit directory are constructed according to DICE - * rules, i.e., that the specifier ID is the GUID's OUI, and that the - * GUID chip ID consists of the 8-bit category ID, the 10-bit product - * ID, and a 22-bit serial number. - */ - fw_csr_iterator_init(&it, unit->directory); - while (fw_csr_iterator_next(&it, &key, &value)) { - switch (key) { - case CSR_SPECIFIER_ID: - vendor = value; - break; - case CSR_MODEL: - model = value; - break; - } - } - if (vendor == OUI_WEISS) - category = WEISS_CATEGORY_ID; - else - category = DICE_CATEGORY_ID; - if (device->config_rom[3] != ((vendor << 8) | category) || - device->config_rom[4] >> 22 != model) - return -ENODEV; - - /* - * Check that the sub address spaces exist and are located inside the - * private address space. The minimum values are chosen so that all - * minimally required registers are included. - */ - err = snd_fw_transaction(unit, TCODE_READ_BLOCK_REQUEST, - DICE_PRIVATE_SPACE, - pointers, sizeof(pointers), 0); - if (err < 0) - return -ENODEV; - for (i = 0; i < ARRAY_SIZE(pointers); ++i) { - value = be32_to_cpu(pointers[i]); - if (value < min_values[i] || value >= 0x40000) - return -ENODEV; - } - - /* We support playback only. Let capture devices be handled by FFADO. */ - err = snd_fw_transaction(unit, TCODE_READ_BLOCK_REQUEST, - DICE_PRIVATE_SPACE + - be32_to_cpu(pointers[2]) * 4, - tx_data, sizeof(tx_data), 0); - if (err < 0 || (tx_data[0] && tx_data[3])) - return -ENODEV; - - /* - * Check that the implemented DICE driver specification major version - * number matches. - */ - err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST, - DICE_PRIVATE_SPACE + - be32_to_cpu(pointers[0]) * 4 + GLOBAL_VERSION, - &version, 4, 0); - if (err < 0) - return -ENODEV; - if ((version & cpu_to_be32(0xff000000)) != cpu_to_be32(0x01000000)) { - dev_err(&unit->device, - "unknown DICE version: 0x%08x\n", be32_to_cpu(version)); - return -ENODEV; - } - - return 0; -} - -static int highest_supported_mode_rate(struct snd_dice *dice, unsigned int mode) -{ - int i; - - for (i = ARRAY_SIZE(dice_rates) - 1; i >= 0; --i) - if ((dice->clock_caps & (1 << i)) && - rate_index_to_mode(i) == mode) - return i; - - return -1; -} - -static int dice_read_mode_params(struct snd_dice *dice, unsigned int mode) -{ - __be32 values[2]; - int rate_index, err; - - rate_index = highest_supported_mode_rate(dice, mode); - if (rate_index < 0) { - dice->rx_channels[mode] = 0; - dice->rx_midi_ports[mode] = 0; - return 0; - } - - err = dice_change_rate(dice, rate_index << CLOCK_RATE_SHIFT); - if (err < 0) - return err; - - err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST, - rx_address(dice, RX_NUMBER_AUDIO), - values, 2 * 4, 0); - if (err < 0) - return err; - - dice->rx_channels[mode] = be32_to_cpu(values[0]); - dice->rx_midi_ports[mode] = be32_to_cpu(values[1]); - - return 0; -} - -static int dice_read_params(struct snd_dice *dice) -{ - __be32 pointers[6]; - __be32 value; - int mode, err; - - err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST, - DICE_PRIVATE_SPACE, - pointers, sizeof(pointers), 0); - if (err < 0) - return err; - - dice->global_offset = be32_to_cpu(pointers[0]) * 4; - dice->rx_offset = be32_to_cpu(pointers[4]) * 4; - - /* some very old firmwares don't tell about their clock support */ - if (be32_to_cpu(pointers[1]) * 4 >= GLOBAL_CLOCK_CAPABILITIES + 4) { - err = snd_fw_transaction( - dice->unit, TCODE_READ_QUADLET_REQUEST, - global_address(dice, GLOBAL_CLOCK_CAPABILITIES), - &value, 4, 0); - if (err < 0) - return err; - dice->clock_caps = be32_to_cpu(value); - } else { - /* this should be supported by any device */ - dice->clock_caps = CLOCK_CAP_RATE_44100 | - CLOCK_CAP_RATE_48000 | - CLOCK_CAP_SOURCE_ARX1 | - CLOCK_CAP_SOURCE_INTERNAL; - } - - for (mode = 2; mode >= 0; --mode) { - err = dice_read_mode_params(dice, mode); - if (err < 0) - return err; - } - - return 0; -} - -static void dice_card_strings(struct snd_dice *dice) -{ - struct snd_card *card = dice->card; - struct fw_device *dev = fw_parent_device(dice->unit); - char vendor[32], model[32]; - unsigned int i; - int err; - - strcpy(card->driver, "DICE"); - - strcpy(card->shortname, "DICE"); - BUILD_BUG_ON(NICK_NAME_SIZE < sizeof(card->shortname)); - err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST, - global_address(dice, GLOBAL_NICK_NAME), - card->shortname, sizeof(card->shortname), 0); - if (err >= 0) { - /* DICE strings are returned in "always-wrong" endianness */ - BUILD_BUG_ON(sizeof(card->shortname) % 4 != 0); - for (i = 0; i < sizeof(card->shortname); i += 4) - swab32s((u32 *)&card->shortname[i]); - card->shortname[sizeof(card->shortname) - 1] = '\0'; - } - - strcpy(vendor, "?"); - fw_csr_string(dev->config_rom + 5, CSR_VENDOR, vendor, sizeof(vendor)); - strcpy(model, "?"); - fw_csr_string(dice->unit->directory, CSR_MODEL, model, sizeof(model)); - snprintf(card->longname, sizeof(card->longname), - "%s %s (serial %u) at %s, S%d", - vendor, model, dev->config_rom[4] & 0x3fffff, - dev_name(&dice->unit->device), 100 << dev->max_speed); - - strcpy(card->mixername, "DICE"); -} - -static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) -{ - struct snd_card *card; - struct snd_dice *dice; - __be32 clock_sel; - int err; - - err = dice_interface_check(unit); - if (err < 0) - return err; - - err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, - sizeof(*dice), &card); - if (err < 0) - return err; - - dice = card->private_data; - dice->card = card; - spin_lock_init(&dice->lock); - mutex_init(&dice->mutex); - dice->unit = unit; - init_completion(&dice->clock_accepted); - init_waitqueue_head(&dice->hwdep_wait); - - dice->notification_handler.length = 4; - dice->notification_handler.address_callback = dice_notification; - dice->notification_handler.callback_data = dice; - err = fw_core_add_address_handler(&dice->notification_handler, - &fw_high_memory_region); - if (err < 0) - goto err_mutex; - - err = dice_owner_set(dice); - if (err < 0) - goto err_notification_handler; - - err = dice_read_params(dice); - if (err < 0) - goto err_owner; - - err = fw_iso_resources_init(&dice->rx_resources, unit); - if (err < 0) - goto err_owner; - dice->rx_resources.channels_mask = 0x00000000ffffffffuLL; - - err = amdtp_stream_init(&dice->rx_stream, unit, AMDTP_OUT_STREAM, - CIP_BLOCKING); - if (err < 0) - goto err_resources; - - card->private_free = dice_card_free; - - dice_card_strings(dice); - - err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST, - global_address(dice, GLOBAL_CLOCK_SELECT), - &clock_sel, 4, 0); - if (err < 0) - goto error; - clock_sel &= cpu_to_be32(~CLOCK_SOURCE_MASK); - clock_sel |= cpu_to_be32(CLOCK_SOURCE_ARX1); - err = snd_fw_transaction(unit, TCODE_WRITE_QUADLET_REQUEST, - global_address(dice, GLOBAL_CLOCK_SELECT), - &clock_sel, 4, 0); - if (err < 0) - goto error; - - err = dice_create_pcm(dice); - if (err < 0) - goto error; - - err = dice_create_hwdep(dice); - if (err < 0) - goto error; - - dice_create_proc(dice); - - err = snd_card_register(card); - if (err < 0) - goto error; - - dev_set_drvdata(&unit->device, dice); - - return 0; - -err_resources: - fw_iso_resources_destroy(&dice->rx_resources); -err_owner: - dice_owner_clear(dice); -err_notification_handler: - fw_core_remove_address_handler(&dice->notification_handler); -err_mutex: - mutex_destroy(&dice->mutex); -error: - snd_card_free(card); - return err; -} - -static void dice_remove(struct fw_unit *unit) -{ - struct snd_dice *dice = dev_get_drvdata(&unit->device); - - amdtp_stream_pcm_abort(&dice->rx_stream); - - snd_card_disconnect(dice->card); - - mutex_lock(&dice->mutex); - - dice_stream_stop(dice); - dice_owner_clear(dice); - - mutex_unlock(&dice->mutex); - - snd_card_free_when_closed(dice->card); -} - -static void dice_bus_reset(struct fw_unit *unit) -{ - struct snd_dice *dice = dev_get_drvdata(&unit->device); - - /* - * On a bus reset, the DICE firmware disables streaming and then goes - * off contemplating its own navel for hundreds of milliseconds before - * it can react to any of our attempts to reenable streaming. This - * means that we lose synchronization anyway, so we force our streams - * to stop so that the application can restart them in an orderly - * manner. - */ - amdtp_stream_pcm_abort(&dice->rx_stream); - - mutex_lock(&dice->mutex); - - dice->global_enabled = false; - dice_stream_stop_packets(dice); - - dice_owner_update(dice); - - fw_iso_resources_update(&dice->rx_resources); - - mutex_unlock(&dice->mutex); -} - -#define DICE_INTERFACE 0x000001 - -static const struct ieee1394_device_id dice_id_table[] = { - { - .match_flags = IEEE1394_MATCH_VERSION, - .version = DICE_INTERFACE, - }, - { } -}; -MODULE_DEVICE_TABLE(ieee1394, dice_id_table); - -static struct fw_driver dice_driver = { - .driver = { - .owner = THIS_MODULE, - .name = KBUILD_MODNAME, - .bus = &fw_bus_type, - }, - .probe = dice_probe, - .update = dice_bus_reset, - .remove = dice_remove, - .id_table = dice_id_table, -}; - -static int __init alsa_dice_init(void) -{ - return driver_register(&dice_driver.driver); -} - -static void __exit alsa_dice_exit(void) -{ - driver_unregister(&dice_driver.driver); -} - -module_init(alsa_dice_init); -module_exit(alsa_dice_exit); diff --git a/sound/firewire/dice/Makefile b/sound/firewire/dice/Makefile new file mode 100644 index 000000000000..af05d7e9119a --- /dev/null +++ b/sound/firewire/dice/Makefile @@ -0,0 +1,2 @@ +snd-dice-objs := dice.o +obj-m += snd-dice.o diff --git a/sound/firewire/dice/dice-interface.h b/sound/firewire/dice/dice-interface.h new file mode 100644 index 000000000000..27b044f84c81 --- /dev/null +++ b/sound/firewire/dice/dice-interface.h @@ -0,0 +1,371 @@ +#ifndef SOUND_FIREWIRE_DICE_INTERFACE_H_INCLUDED +#define SOUND_FIREWIRE_DICE_INTERFACE_H_INCLUDED + +/* + * DICE device interface definitions + */ + +/* + * Generally, all registers can be read like memory, i.e., with quadlet read or + * block read transactions with at least quadlet-aligned offset and length. + * Writes are not allowed except where noted; quadlet-sized registers must be + * written with a quadlet write transaction. + * + * All values are in big endian. The DICE firmware runs on a little-endian CPU + * and just byte-swaps _all_ quadlets on the bus, so values without endianness + * (e.g. strings) get scrambled and must be byte-swapped again by the driver. + */ + +/* + * Streaming is handled by the "DICE driver" interface. Its registers are + * located in this private address space. + */ +#define DICE_PRIVATE_SPACE 0xffffe0000000uLL + +/* + * The registers are organized in several sections, which are organized + * separately to allow them to be extended individually. Whether a register is + * supported can be detected by checking its offset against its section's size. + * + * The section offset values are relative to DICE_PRIVATE_SPACE; the offset/ + * size values are measured in quadlets. Read-only. + */ +#define DICE_GLOBAL_OFFSET 0x00 +#define DICE_GLOBAL_SIZE 0x04 +#define DICE_TX_OFFSET 0x08 +#define DICE_TX_SIZE 0x0c +#define DICE_RX_OFFSET 0x10 +#define DICE_RX_SIZE 0x14 +#define DICE_EXT_SYNC_OFFSET 0x18 +#define DICE_EXT_SYNC_SIZE 0x1c +#define DICE_UNUSED2_OFFSET 0x20 +#define DICE_UNUSED2_SIZE 0x24 + +/* + * Global settings. + */ + +/* + * Stores the full 64-bit address (node ID and offset in the node's address + * space) where the device will send notifications. Must be changed with + * a compare/swap transaction by the owner. This register is automatically + * cleared on a bus reset. + */ +#define GLOBAL_OWNER 0x000 +#define OWNER_NO_OWNER 0xffff000000000000uLL +#define OWNER_NODE_SHIFT 48 + +/* + * A bitmask with asynchronous events; read-only. When any event(s) happen, + * the bits of previous events are cleared, and the value of this register is + * also written to the address stored in the owner register. + */ +#define GLOBAL_NOTIFICATION 0x008 +/* Some registers in the Rx/Tx sections may have changed. */ +#define NOTIFY_RX_CFG_CHG 0x00000001 +#define NOTIFY_TX_CFG_CHG 0x00000002 +/* Lock status of the current clock source may have changed. */ +#define NOTIFY_LOCK_CHG 0x00000010 +/* Write to the clock select register has been finished. */ +#define NOTIFY_CLOCK_ACCEPTED 0x00000020 +/* Lock status of some clock source has changed. */ +#define NOTIFY_EXT_STATUS 0x00000040 +/* Other bits may be used for device-specific events. */ + +/* + * A name that can be customized for each device; read/write. Padded with zero + * bytes. Quadlets are byte-swapped. The encoding is whatever the host driver + * happens to be using. + */ +#define GLOBAL_NICK_NAME 0x00c +#define NICK_NAME_SIZE 64 + +/* + * The current sample rate and clock source; read/write. Whether a clock + * source or sample rate is supported is device-specific; the internal clock + * source is always available. Low/mid/high = up to 48/96/192 kHz. This + * register can be changed even while streams are running. + */ +#define GLOBAL_CLOCK_SELECT 0x04c +#define CLOCK_SOURCE_MASK 0x000000ff +#define CLOCK_SOURCE_AES1 0x00000000 +#define CLOCK_SOURCE_AES2 0x00000001 +#define CLOCK_SOURCE_AES3 0x00000002 +#define CLOCK_SOURCE_AES4 0x00000003 +#define CLOCK_SOURCE_AES_ANY 0x00000004 +#define CLOCK_SOURCE_ADAT 0x00000005 +#define CLOCK_SOURCE_TDIF 0x00000006 +#define CLOCK_SOURCE_WC 0x00000007 +#define CLOCK_SOURCE_ARX1 0x00000008 +#define CLOCK_SOURCE_ARX2 0x00000009 +#define CLOCK_SOURCE_ARX3 0x0000000a +#define CLOCK_SOURCE_ARX4 0x0000000b +#define CLOCK_SOURCE_INTERNAL 0x0000000c +#define CLOCK_RATE_MASK 0x0000ff00 +#define CLOCK_RATE_32000 0x00000000 +#define CLOCK_RATE_44100 0x00000100 +#define CLOCK_RATE_48000 0x00000200 +#define CLOCK_RATE_88200 0x00000300 +#define CLOCK_RATE_96000 0x00000400 +#define CLOCK_RATE_176400 0x00000500 +#define CLOCK_RATE_192000 0x00000600 +#define CLOCK_RATE_ANY_LOW 0x00000700 +#define CLOCK_RATE_ANY_MID 0x00000800 +#define CLOCK_RATE_ANY_HIGH 0x00000900 +#define CLOCK_RATE_NONE 0x00000a00 +#define CLOCK_RATE_SHIFT 8 + +/* + * Enable streaming; read/write. Writing a non-zero value (re)starts all + * streams that have a valid iso channel set; zero stops all streams. The + * streams' parameters must be configured before starting. This register is + * automatically cleared on a bus reset. + */ +#define GLOBAL_ENABLE 0x050 + +/* + * Status of the sample clock; read-only. + */ +#define GLOBAL_STATUS 0x054 +/* The current clock source is locked. */ +#define STATUS_SOURCE_LOCKED 0x00000001 +/* The actual sample rate; CLOCK_RATE_32000-_192000 or _NONE. */ +#define STATUS_NOMINAL_RATE_MASK 0x0000ff00 + +/* + * Status of all clock sources; read-only. + */ +#define GLOBAL_EXTENDED_STATUS 0x058 +/* + * The _LOCKED bits always show the current status; any change generates + * a notification. + */ +#define EXT_STATUS_AES1_LOCKED 0x00000001 +#define EXT_STATUS_AES2_LOCKED 0x00000002 +#define EXT_STATUS_AES3_LOCKED 0x00000004 +#define EXT_STATUS_AES4_LOCKED 0x00000008 +#define EXT_STATUS_ADAT_LOCKED 0x00000010 +#define EXT_STATUS_TDIF_LOCKED 0x00000020 +#define EXT_STATUS_ARX1_LOCKED 0x00000040 +#define EXT_STATUS_ARX2_LOCKED 0x00000080 +#define EXT_STATUS_ARX3_LOCKED 0x00000100 +#define EXT_STATUS_ARX4_LOCKED 0x00000200 +#define EXT_STATUS_WC_LOCKED 0x00000400 +/* + * The _SLIP bits do not generate notifications; a set bit indicates that an + * error occurred since the last time when this register was read with + * a quadlet read transaction. + */ +#define EXT_STATUS_AES1_SLIP 0x00010000 +#define EXT_STATUS_AES2_SLIP 0x00020000 +#define EXT_STATUS_AES3_SLIP 0x00040000 +#define EXT_STATUS_AES4_SLIP 0x00080000 +#define EXT_STATUS_ADAT_SLIP 0x00100000 +#define EXT_STATUS_TDIF_SLIP 0x00200000 +#define EXT_STATUS_ARX1_SLIP 0x00400000 +#define EXT_STATUS_ARX2_SLIP 0x00800000 +#define EXT_STATUS_ARX3_SLIP 0x01000000 +#define EXT_STATUS_ARX4_SLIP 0x02000000 +#define EXT_STATUS_WC_SLIP 0x04000000 + +/* + * The measured rate of the current clock source, in Hz; read-only. + */ +#define GLOBAL_SAMPLE_RATE 0x05c + +/* + * The version of the DICE driver specification that this device conforms to; + * read-only. + */ +#define GLOBAL_VERSION 0x060 + +/* Some old firmware versions do not have the following global registers: */ + +/* + * Supported sample rates and clock sources; read-only. + */ +#define GLOBAL_CLOCK_CAPABILITIES 0x064 +#define CLOCK_CAP_RATE_32000 0x00000001 +#define CLOCK_CAP_RATE_44100 0x00000002 +#define CLOCK_CAP_RATE_48000 0x00000004 +#define CLOCK_CAP_RATE_88200 0x00000008 +#define CLOCK_CAP_RATE_96000 0x00000010 +#define CLOCK_CAP_RATE_176400 0x00000020 +#define CLOCK_CAP_RATE_192000 0x00000040 +#define CLOCK_CAP_SOURCE_AES1 0x00010000 +#define CLOCK_CAP_SOURCE_AES2 0x00020000 +#define CLOCK_CAP_SOURCE_AES3 0x00040000 +#define CLOCK_CAP_SOURCE_AES4 0x00080000 +#define CLOCK_CAP_SOURCE_AES_ANY 0x00100000 +#define CLOCK_CAP_SOURCE_ADAT 0x00200000 +#define CLOCK_CAP_SOURCE_TDIF 0x00400000 +#define CLOCK_CAP_SOURCE_WC 0x00800000 +#define CLOCK_CAP_SOURCE_ARX1 0x01000000 +#define CLOCK_CAP_SOURCE_ARX2 0x02000000 +#define CLOCK_CAP_SOURCE_ARX3 0x04000000 +#define CLOCK_CAP_SOURCE_ARX4 0x08000000 +#define CLOCK_CAP_SOURCE_INTERNAL 0x10000000 + +/* + * Names of all clock sources; read-only. Quadlets are byte-swapped. Names + * are separated with one backslash, the list is terminated with two + * backslashes. Unused clock sources are included. + */ +#define GLOBAL_CLOCK_SOURCE_NAMES 0x068 +#define CLOCK_SOURCE_NAMES_SIZE 256 + +/* + * Capture stream settings. This section includes the number/size registers + * and the registers of all streams. + */ + +/* + * The number of supported capture streams; read-only. + */ +#define TX_NUMBER 0x000 + +/* + * The size of one stream's register block, in quadlets; read-only. The + * registers of the first stream follow immediately afterwards; the registers + * of the following streams are offset by this register's value. + */ +#define TX_SIZE 0x004 + +/* + * The isochronous channel number on which packets are sent, or -1 if the + * stream is not to be used; read/write. + */ +#define TX_ISOCHRONOUS 0x008 + +/* + * The number of audio channels; read-only. There will be one quadlet per + * channel; the first channel is the first quadlet in a data block. + */ +#define TX_NUMBER_AUDIO 0x00c + +/* + * The number of MIDI ports, 0-8; read-only. If > 0, there will be one + * additional quadlet in each data block, following the audio quadlets. + */ +#define TX_NUMBER_MIDI 0x010 + +/* + * The speed at which the packets are sent, SCODE_100-_400; read/write. + */ +#define TX_SPEED 0x014 + +/* + * Names of all audio channels; read-only. Quadlets are byte-swapped. Names + * are separated with one backslash, the list is terminated with two + * backslashes. + */ +#define TX_NAMES 0x018 +#define TX_NAMES_SIZE 256 + +/* + * Audio IEC60958 capabilities; read-only. Bitmask with one bit per audio + * channel. + */ +#define TX_AC3_CAPABILITIES 0x118 + +/* + * Send audio data with IEC60958 label; read/write. Bitmask with one bit per + * audio channel. This register can be changed even while the stream is + * running. + */ +#define TX_AC3_ENABLE 0x11c + +/* + * Playback stream settings. This section includes the number/size registers + * and the registers of all streams. + */ + +/* + * The number of supported playback streams; read-only. + */ +#define RX_NUMBER 0x000 + +/* + * The size of one stream's register block, in quadlets; read-only. The + * registers of the first stream follow immediately afterwards; the registers + * of the following streams are offset by this register's value. + */ +#define RX_SIZE 0x004 + +/* + * The isochronous channel number on which packets are received, or -1 if the + * stream is not to be used; read/write. + */ +#define RX_ISOCHRONOUS 0x008 + +/* + * Index of first quadlet to be interpreted; read/write. If > 0, that many + * quadlets at the beginning of each data block will be ignored, and all the + * audio and MIDI quadlets will follow. + */ +#define RX_SEQ_START 0x00c + +/* + * The number of audio channels; read-only. There will be one quadlet per + * channel. + */ +#define RX_NUMBER_AUDIO 0x010 + +/* + * The number of MIDI ports, 0-8; read-only. If > 0, there will be one + * additional quadlet in each data block, following the audio quadlets. + */ +#define RX_NUMBER_MIDI 0x014 + +/* + * Names of all audio channels; read-only. Quadlets are byte-swapped. Names + * are separated with one backslash, the list is terminated with two + * backslashes. + */ +#define RX_NAMES 0x018 +#define RX_NAMES_SIZE 256 + +/* + * Audio IEC60958 capabilities; read-only. Bitmask with one bit per audio + * channel. + */ +#define RX_AC3_CAPABILITIES 0x118 + +/* + * Receive audio data with IEC60958 label; read/write. Bitmask with one bit + * per audio channel. This register can be changed even while the stream is + * running. + */ +#define RX_AC3_ENABLE 0x11c + +/* + * Extended synchronization information. + * This section can be read completely with a block read request. + */ + +/* + * Current clock source; read-only. + */ +#define EXT_SYNC_CLOCK_SOURCE 0x000 + +/* + * Clock source is locked (boolean); read-only. + */ +#define EXT_SYNC_LOCKED 0x004 + +/* + * Current sample rate (CLOCK_RATE_* >> CLOCK_RATE_SHIFT), _32000-_192000 or + * _NONE; read-only. + */ +#define EXT_SYNC_RATE 0x008 + +/* + * ADAT user data bits; read-only. + */ +#define EXT_SYNC_ADAT_USER_DATA 0x00c +/* The data bits, if available. */ +#define ADAT_USER_DATA_MASK 0x0f +/* The data bits are not available. */ +#define ADAT_USER_DATA_NO_DATA 0x10 + +#endif diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c new file mode 100644 index 000000000000..d3ec778878af --- /dev/null +++ b/sound/firewire/dice/dice.c @@ -0,0 +1,1512 @@ +/* + * TC Applied Technologies Digital Interface Communications Engine driver + * + * Copyright (c) Clemens Ladisch + * Licensed under the terms of the GNU General Public License, version 2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../amdtp.h" +#include "../iso-resources.h" +#include "../lib.h" +#include "dice-interface.h" + + +struct snd_dice { + struct snd_card *card; + struct fw_unit *unit; + spinlock_t lock; + struct mutex mutex; + unsigned int global_offset; + unsigned int rx_offset; + unsigned int clock_caps; + unsigned int rx_channels[3]; + unsigned int rx_midi_ports[3]; + struct fw_address_handler notification_handler; + int owner_generation; + int dev_lock_count; /* > 0 driver, < 0 userspace */ + bool dev_lock_changed; + bool global_enabled; + struct completion clock_accepted; + wait_queue_head_t hwdep_wait; + u32 notification_bits; + struct fw_iso_resources rx_resources; + struct amdtp_stream rx_stream; +}; + +MODULE_DESCRIPTION("DICE driver"); +MODULE_AUTHOR("Clemens Ladisch "); +MODULE_LICENSE("GPL v2"); + +static const unsigned int dice_rates[] = { + /* mode 0 */ + [0] = 32000, + [1] = 44100, + [2] = 48000, + /* mode 1 */ + [3] = 88200, + [4] = 96000, + /* mode 2 */ + [5] = 176400, + [6] = 192000, +}; + +static unsigned int rate_to_index(unsigned int rate) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(dice_rates); ++i) + if (dice_rates[i] == rate) + return i; + + return 0; +} + +static unsigned int rate_index_to_mode(unsigned int rate_index) +{ + return ((int)rate_index - 1) / 2; +} + +static void dice_lock_changed(struct snd_dice *dice) +{ + dice->dev_lock_changed = true; + wake_up(&dice->hwdep_wait); +} + +static int dice_try_lock(struct snd_dice *dice) +{ + int err; + + spin_lock_irq(&dice->lock); + + if (dice->dev_lock_count < 0) { + err = -EBUSY; + goto out; + } + + if (dice->dev_lock_count++ == 0) + dice_lock_changed(dice); + err = 0; + +out: + spin_unlock_irq(&dice->lock); + + return err; +} + +static void dice_unlock(struct snd_dice *dice) +{ + spin_lock_irq(&dice->lock); + + if (WARN_ON(dice->dev_lock_count <= 0)) + goto out; + + if (--dice->dev_lock_count == 0) + dice_lock_changed(dice); + +out: + spin_unlock_irq(&dice->lock); +} + +static inline u64 global_address(struct snd_dice *dice, unsigned int offset) +{ + return DICE_PRIVATE_SPACE + dice->global_offset + offset; +} + +/* TODO: rx index */ +static inline u64 rx_address(struct snd_dice *dice, unsigned int offset) +{ + return DICE_PRIVATE_SPACE + dice->rx_offset + offset; +} + +static int dice_owner_set(struct snd_dice *dice) +{ + struct fw_device *device = fw_parent_device(dice->unit); + __be64 *buffer; + int err, errors = 0; + + buffer = kmalloc(2 * 8, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + for (;;) { + buffer[0] = cpu_to_be64(OWNER_NO_OWNER); + buffer[1] = cpu_to_be64( + ((u64)device->card->node_id << OWNER_NODE_SHIFT) | + dice->notification_handler.offset); + + dice->owner_generation = device->generation; + smp_rmb(); /* node_id vs. generation */ + err = snd_fw_transaction(dice->unit, + TCODE_LOCK_COMPARE_SWAP, + global_address(dice, GLOBAL_OWNER), + buffer, 2 * 8, + FW_FIXED_GENERATION | + dice->owner_generation); + + if (err == 0) { + if (buffer[0] != cpu_to_be64(OWNER_NO_OWNER)) { + dev_err(&dice->unit->device, + "device is already in use\n"); + err = -EBUSY; + } + break; + } + if (err != -EAGAIN || ++errors >= 3) + break; + + msleep(20); + } + + kfree(buffer); + + return err; +} + +static int dice_owner_update(struct snd_dice *dice) +{ + struct fw_device *device = fw_parent_device(dice->unit); + __be64 *buffer; + int err; + + if (dice->owner_generation == -1) + return 0; + + buffer = kmalloc(2 * 8, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + buffer[0] = cpu_to_be64(OWNER_NO_OWNER); + buffer[1] = cpu_to_be64( + ((u64)device->card->node_id << OWNER_NODE_SHIFT) | + dice->notification_handler.offset); + + dice->owner_generation = device->generation; + smp_rmb(); /* node_id vs. generation */ + err = snd_fw_transaction(dice->unit, TCODE_LOCK_COMPARE_SWAP, + global_address(dice, GLOBAL_OWNER), + buffer, 2 * 8, + FW_FIXED_GENERATION | dice->owner_generation); + + if (err == 0) { + if (buffer[0] != cpu_to_be64(OWNER_NO_OWNER)) { + dev_err(&dice->unit->device, + "device is already in use\n"); + err = -EBUSY; + } + } else if (err == -EAGAIN) { + err = 0; /* try again later */ + } + + kfree(buffer); + + if (err < 0) + dice->owner_generation = -1; + + return err; +} + +static void dice_owner_clear(struct snd_dice *dice) +{ + struct fw_device *device = fw_parent_device(dice->unit); + __be64 *buffer; + + buffer = kmalloc(2 * 8, GFP_KERNEL); + if (!buffer) + return; + + buffer[0] = cpu_to_be64( + ((u64)device->card->node_id << OWNER_NODE_SHIFT) | + dice->notification_handler.offset); + buffer[1] = cpu_to_be64(OWNER_NO_OWNER); + snd_fw_transaction(dice->unit, TCODE_LOCK_COMPARE_SWAP, + global_address(dice, GLOBAL_OWNER), + buffer, 2 * 8, FW_QUIET | + FW_FIXED_GENERATION | dice->owner_generation); + + kfree(buffer); + + dice->owner_generation = -1; +} + +static int dice_enable_set(struct snd_dice *dice) +{ + __be32 value; + int err; + + value = cpu_to_be32(1); + err = snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST, + global_address(dice, GLOBAL_ENABLE), + &value, 4, + FW_FIXED_GENERATION | dice->owner_generation); + if (err < 0) + return err; + + dice->global_enabled = true; + + return 0; +} + +static void dice_enable_clear(struct snd_dice *dice) +{ + __be32 value; + + if (!dice->global_enabled) + return; + + value = 0; + snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST, + global_address(dice, GLOBAL_ENABLE), + &value, 4, FW_QUIET | + FW_FIXED_GENERATION | dice->owner_generation); + + dice->global_enabled = false; +} + +static void dice_notification(struct fw_card *card, struct fw_request *request, + int tcode, int destination, int source, + int generation, unsigned long long offset, + void *data, size_t length, void *callback_data) +{ + struct snd_dice *dice = callback_data; + u32 bits; + unsigned long flags; + + if (tcode != TCODE_WRITE_QUADLET_REQUEST) { + fw_send_response(card, request, RCODE_TYPE_ERROR); + return; + } + if ((offset & 3) != 0) { + fw_send_response(card, request, RCODE_ADDRESS_ERROR); + return; + } + + bits = be32_to_cpup(data); + + spin_lock_irqsave(&dice->lock, flags); + dice->notification_bits |= bits; + spin_unlock_irqrestore(&dice->lock, flags); + + fw_send_response(card, request, RCODE_COMPLETE); + + if (bits & NOTIFY_CLOCK_ACCEPTED) + complete(&dice->clock_accepted); + wake_up(&dice->hwdep_wait); +} + +static int dice_rate_constraint(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct snd_dice *dice = rule->private; + const struct snd_interval *channels = + hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_interval *rate = + hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval allowed_rates = { + .min = UINT_MAX, .max = 0, .integer = 1 + }; + unsigned int i, mode; + + for (i = 0; i < ARRAY_SIZE(dice_rates); ++i) { + mode = rate_index_to_mode(i); + if ((dice->clock_caps & (1 << i)) && + snd_interval_test(channels, dice->rx_channels[mode])) { + allowed_rates.min = min(allowed_rates.min, + dice_rates[i]); + allowed_rates.max = max(allowed_rates.max, + dice_rates[i]); + } + } + + return snd_interval_refine(rate, &allowed_rates); +} + +static int dice_channels_constraint(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct snd_dice *dice = rule->private; + const struct snd_interval *rate = + hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = + hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_interval allowed_channels = { + .min = UINT_MAX, .max = 0, .integer = 1 + }; + unsigned int i, mode; + + for (i = 0; i < ARRAY_SIZE(dice_rates); ++i) + if ((dice->clock_caps & (1 << i)) && + snd_interval_test(rate, dice_rates[i])) { + mode = rate_index_to_mode(i); + allowed_channels.min = min(allowed_channels.min, + dice->rx_channels[mode]); + allowed_channels.max = max(allowed_channels.max, + dice->rx_channels[mode]); + } + + return snd_interval_refine(channels, &allowed_channels); +} + +static int dice_open(struct snd_pcm_substream *substream) +{ + static const struct snd_pcm_hardware hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_BATCH | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER, + .formats = AMDTP_OUT_PCM_FORMAT_BITS, + .channels_min = UINT_MAX, + .channels_max = 0, + .buffer_bytes_max = 16 * 1024 * 1024, + .period_bytes_min = 1, + .period_bytes_max = UINT_MAX, + .periods_min = 1, + .periods_max = UINT_MAX, + }; + struct snd_dice *dice = substream->private_data; + struct snd_pcm_runtime *runtime = substream->runtime; + unsigned int i; + int err; + + err = dice_try_lock(dice); + if (err < 0) + goto error; + + runtime->hw = hardware; + + for (i = 0; i < ARRAY_SIZE(dice_rates); ++i) + if (dice->clock_caps & (1 << i)) + runtime->hw.rates |= + snd_pcm_rate_to_rate_bit(dice_rates[i]); + snd_pcm_limit_hw_rates(runtime); + + for (i = 0; i < 3; ++i) + if (dice->rx_channels[i]) { + runtime->hw.channels_min = min(runtime->hw.channels_min, + dice->rx_channels[i]); + runtime->hw.channels_max = max(runtime->hw.channels_max, + dice->rx_channels[i]); + } + + err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + dice_rate_constraint, dice, + SNDRV_PCM_HW_PARAM_CHANNELS, -1); + if (err < 0) + goto err_lock; + err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + dice_channels_constraint, dice, + SNDRV_PCM_HW_PARAM_RATE, -1); + if (err < 0) + goto err_lock; + + err = amdtp_stream_add_pcm_hw_constraints(&dice->rx_stream, runtime); + if (err < 0) + goto err_lock; + + return 0; + +err_lock: + dice_unlock(dice); +error: + return err; +} + +static int dice_close(struct snd_pcm_substream *substream) +{ + struct snd_dice *dice = substream->private_data; + + dice_unlock(dice); + + return 0; +} + +static int dice_stream_start_packets(struct snd_dice *dice) +{ + int err; + + if (amdtp_stream_running(&dice->rx_stream)) + return 0; + + err = amdtp_stream_start(&dice->rx_stream, dice->rx_resources.channel, + fw_parent_device(dice->unit)->max_speed); + if (err < 0) + return err; + + err = dice_enable_set(dice); + if (err < 0) { + amdtp_stream_stop(&dice->rx_stream); + return err; + } + + return 0; +} + +static int dice_stream_start(struct snd_dice *dice) +{ + __be32 channel; + int err; + + if (!dice->rx_resources.allocated) { + err = fw_iso_resources_allocate(&dice->rx_resources, + amdtp_stream_get_max_payload(&dice->rx_stream), + fw_parent_device(dice->unit)->max_speed); + if (err < 0) + goto error; + + channel = cpu_to_be32(dice->rx_resources.channel); + err = snd_fw_transaction(dice->unit, + TCODE_WRITE_QUADLET_REQUEST, + rx_address(dice, RX_ISOCHRONOUS), + &channel, 4, 0); + if (err < 0) + goto err_resources; + } + + err = dice_stream_start_packets(dice); + if (err < 0) + goto err_rx_channel; + + return 0; + +err_rx_channel: + channel = cpu_to_be32((u32)-1); + snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST, + rx_address(dice, RX_ISOCHRONOUS), &channel, 4, 0); +err_resources: + fw_iso_resources_free(&dice->rx_resources); +error: + return err; +} + +static void dice_stream_stop_packets(struct snd_dice *dice) +{ + if (amdtp_stream_running(&dice->rx_stream)) { + dice_enable_clear(dice); + amdtp_stream_stop(&dice->rx_stream); + } +} + +static void dice_stream_stop(struct snd_dice *dice) +{ + __be32 channel; + + dice_stream_stop_packets(dice); + + if (!dice->rx_resources.allocated) + return; + + channel = cpu_to_be32((u32)-1); + snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST, + rx_address(dice, RX_ISOCHRONOUS), &channel, 4, 0); + + fw_iso_resources_free(&dice->rx_resources); +} + +static int dice_change_rate(struct snd_dice *dice, unsigned int clock_rate) +{ + __be32 value; + int err; + + reinit_completion(&dice->clock_accepted); + + value = cpu_to_be32(clock_rate | CLOCK_SOURCE_ARX1); + err = snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST, + global_address(dice, GLOBAL_CLOCK_SELECT), + &value, 4, 0); + if (err < 0) + return err; + + if (!wait_for_completion_timeout(&dice->clock_accepted, + msecs_to_jiffies(100))) + dev_warn(&dice->unit->device, "clock change timed out\n"); + + return 0; +} + +static int dice_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct snd_dice *dice = substream->private_data; + unsigned int rate_index, mode, rate, channels, i; + int err; + + mutex_lock(&dice->mutex); + dice_stream_stop(dice); + mutex_unlock(&dice->mutex); + + err = snd_pcm_lib_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); + if (err < 0) + return err; + + rate = params_rate(hw_params); + rate_index = rate_to_index(rate); + err = dice_change_rate(dice, rate_index << CLOCK_RATE_SHIFT); + if (err < 0) + return err; + + /* + * At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in + * one data block of AMDTP packet. Thus sampling transfer frequency is + * a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are + * transferred on AMDTP packets at 96 kHz. Two successive samples of a + * channel are stored consecutively in the packet. This quirk is called + * as 'Dual Wire'. + * For this quirk, blocking mode is required and PCM buffer size should + * be aligned to SYT_INTERVAL. + */ + channels = params_channels(hw_params); + if (rate_index > 4) { + if (channels > AMDTP_MAX_CHANNELS_FOR_PCM / 2) { + err = -ENOSYS; + return err; + } + + rate /= 2; + channels *= 2; + dice->rx_stream.double_pcm_frames = true; + } else { + dice->rx_stream.double_pcm_frames = false; + } + + mode = rate_index_to_mode(rate_index); + amdtp_stream_set_parameters(&dice->rx_stream, rate, channels, + dice->rx_midi_ports[mode]); + if (rate_index > 4) { + channels /= 2; + + for (i = 0; i < channels; i++) { + dice->rx_stream.pcm_positions[i] = i * 2; + dice->rx_stream.pcm_positions[i + channels] = i * 2 + 1; + } + } + + amdtp_stream_set_pcm_format(&dice->rx_stream, + params_format(hw_params)); + + return 0; +} + +static int dice_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_dice *dice = substream->private_data; + + mutex_lock(&dice->mutex); + dice_stream_stop(dice); + mutex_unlock(&dice->mutex); + + return snd_pcm_lib_free_vmalloc_buffer(substream); +} + +static int dice_prepare(struct snd_pcm_substream *substream) +{ + struct snd_dice *dice = substream->private_data; + int err; + + mutex_lock(&dice->mutex); + + if (amdtp_streaming_error(&dice->rx_stream)) + dice_stream_stop_packets(dice); + + err = dice_stream_start(dice); + if (err < 0) { + mutex_unlock(&dice->mutex); + return err; + } + + mutex_unlock(&dice->mutex); + + amdtp_stream_pcm_prepare(&dice->rx_stream); + + return 0; +} + +static int dice_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_dice *dice = substream->private_data; + struct snd_pcm_substream *pcm; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + pcm = substream; + break; + case SNDRV_PCM_TRIGGER_STOP: + pcm = NULL; + break; + default: + return -EINVAL; + } + amdtp_stream_pcm_trigger(&dice->rx_stream, pcm); + + return 0; +} + +static snd_pcm_uframes_t dice_pointer(struct snd_pcm_substream *substream) +{ + struct snd_dice *dice = substream->private_data; + + return amdtp_stream_pcm_pointer(&dice->rx_stream); +} + +static int dice_create_pcm(struct snd_dice *dice) +{ + static struct snd_pcm_ops ops = { + .open = dice_open, + .close = dice_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = dice_hw_params, + .hw_free = dice_hw_free, + .prepare = dice_prepare, + .trigger = dice_trigger, + .pointer = dice_pointer, + .page = snd_pcm_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, + }; + struct snd_pcm *pcm; + int err; + + err = snd_pcm_new(dice->card, "DICE", 0, 1, 0, &pcm); + if (err < 0) + return err; + pcm->private_data = dice; + strcpy(pcm->name, dice->card->shortname); + pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->ops = &ops; + + return 0; +} + +static long dice_hwdep_read(struct snd_hwdep *hwdep, char __user *buf, + long count, loff_t *offset) +{ + struct snd_dice *dice = hwdep->private_data; + DEFINE_WAIT(wait); + union snd_firewire_event event; + + spin_lock_irq(&dice->lock); + + while (!dice->dev_lock_changed && dice->notification_bits == 0) { + prepare_to_wait(&dice->hwdep_wait, &wait, TASK_INTERRUPTIBLE); + spin_unlock_irq(&dice->lock); + schedule(); + finish_wait(&dice->hwdep_wait, &wait); + if (signal_pending(current)) + return -ERESTARTSYS; + spin_lock_irq(&dice->lock); + } + + memset(&event, 0, sizeof(event)); + if (dice->dev_lock_changed) { + event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS; + event.lock_status.status = dice->dev_lock_count > 0; + dice->dev_lock_changed = false; + + count = min_t(long, count, sizeof(event.lock_status)); + } else { + event.dice_notification.type = + SNDRV_FIREWIRE_EVENT_DICE_NOTIFICATION; + event.dice_notification.notification = dice->notification_bits; + dice->notification_bits = 0; + + count = min_t(long, count, sizeof(event.dice_notification)); + } + + spin_unlock_irq(&dice->lock); + + if (copy_to_user(buf, &event, count)) + return -EFAULT; + + return count; +} + +static unsigned int dice_hwdep_poll(struct snd_hwdep *hwdep, struct file *file, + poll_table *wait) +{ + struct snd_dice *dice = hwdep->private_data; + unsigned int events; + + poll_wait(file, &dice->hwdep_wait, wait); + + spin_lock_irq(&dice->lock); + if (dice->dev_lock_changed || dice->notification_bits != 0) + events = POLLIN | POLLRDNORM; + else + events = 0; + spin_unlock_irq(&dice->lock); + + return events; +} + +static int dice_hwdep_get_info(struct snd_dice *dice, void __user *arg) +{ + struct fw_device *dev = fw_parent_device(dice->unit); + struct snd_firewire_get_info info; + + memset(&info, 0, sizeof(info)); + info.type = SNDRV_FIREWIRE_TYPE_DICE; + info.card = dev->card->index; + *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]); + *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]); + strlcpy(info.device_name, dev_name(&dev->device), + sizeof(info.device_name)); + + if (copy_to_user(arg, &info, sizeof(info))) + return -EFAULT; + + return 0; +} + +static int dice_hwdep_lock(struct snd_dice *dice) +{ + int err; + + spin_lock_irq(&dice->lock); + + if (dice->dev_lock_count == 0) { + dice->dev_lock_count = -1; + err = 0; + } else { + err = -EBUSY; + } + + spin_unlock_irq(&dice->lock); + + return err; +} + +static int dice_hwdep_unlock(struct snd_dice *dice) +{ + int err; + + spin_lock_irq(&dice->lock); + + if (dice->dev_lock_count == -1) { + dice->dev_lock_count = 0; + err = 0; + } else { + err = -EBADFD; + } + + spin_unlock_irq(&dice->lock); + + return err; +} + +static int dice_hwdep_release(struct snd_hwdep *hwdep, struct file *file) +{ + struct snd_dice *dice = hwdep->private_data; + + spin_lock_irq(&dice->lock); + if (dice->dev_lock_count == -1) + dice->dev_lock_count = 0; + spin_unlock_irq(&dice->lock); + + return 0; +} + +static int dice_hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct snd_dice *dice = hwdep->private_data; + + switch (cmd) { + case SNDRV_FIREWIRE_IOCTL_GET_INFO: + return dice_hwdep_get_info(dice, (void __user *)arg); + case SNDRV_FIREWIRE_IOCTL_LOCK: + return dice_hwdep_lock(dice); + case SNDRV_FIREWIRE_IOCTL_UNLOCK: + return dice_hwdep_unlock(dice); + default: + return -ENOIOCTLCMD; + } +} + +#ifdef CONFIG_COMPAT +static int dice_hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file, + unsigned int cmd, unsigned long arg) +{ + return dice_hwdep_ioctl(hwdep, file, cmd, + (unsigned long)compat_ptr(arg)); +} +#else +#define dice_hwdep_compat_ioctl NULL +#endif + +static int dice_create_hwdep(struct snd_dice *dice) +{ + static const struct snd_hwdep_ops ops = { + .read = dice_hwdep_read, + .release = dice_hwdep_release, + .poll = dice_hwdep_poll, + .ioctl = dice_hwdep_ioctl, + .ioctl_compat = dice_hwdep_compat_ioctl, + }; + struct snd_hwdep *hwdep; + int err; + + err = snd_hwdep_new(dice->card, "DICE", 0, &hwdep); + if (err < 0) + return err; + strcpy(hwdep->name, "DICE"); + hwdep->iface = SNDRV_HWDEP_IFACE_FW_DICE; + hwdep->ops = ops; + hwdep->private_data = dice; + hwdep->exclusive = true; + + return 0; +} + +static int dice_proc_read_mem(struct snd_dice *dice, void *buffer, + unsigned int offset_q, unsigned int quadlets) +{ + unsigned int i; + int err; + + err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST, + DICE_PRIVATE_SPACE + 4 * offset_q, + buffer, 4 * quadlets, 0); + if (err < 0) + return err; + + for (i = 0; i < quadlets; ++i) + be32_to_cpus(&((u32 *)buffer)[i]); + + return 0; +} + +static const char *str_from_array(const char *const strs[], unsigned int count, + unsigned int i) +{ + if (i < count) + return strs[i]; + + return "(unknown)"; +} + +static void dice_proc_fixup_string(char *s, unsigned int size) +{ + unsigned int i; + + for (i = 0; i < size; i += 4) + cpu_to_le32s((u32 *)(s + i)); + + for (i = 0; i < size - 2; ++i) { + if (s[i] == '\0') + return; + if (s[i] == '\\' && s[i + 1] == '\\') { + s[i + 2] = '\0'; + return; + } + } + s[size - 1] = '\0'; +} + +static void dice_proc_read(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + static const char *const section_names[5] = { + "global", "tx", "rx", "ext_sync", "unused2" + }; + static const char *const clock_sources[] = { + "aes1", "aes2", "aes3", "aes4", "aes", "adat", "tdif", + "wc", "arx1", "arx2", "arx3", "arx4", "internal" + }; + static const char *const rates[] = { + "32000", "44100", "48000", "88200", "96000", "176400", "192000", + "any low", "any mid", "any high", "none" + }; + struct snd_dice *dice = entry->private_data; + u32 sections[ARRAY_SIZE(section_names) * 2]; + struct { + u32 number; + u32 size; + } tx_rx_header; + union { + struct { + u32 owner_hi, owner_lo; + u32 notification; + char nick_name[NICK_NAME_SIZE]; + u32 clock_select; + u32 enable; + u32 status; + u32 extended_status; + u32 sample_rate; + u32 version; + u32 clock_caps; + char clock_source_names[CLOCK_SOURCE_NAMES_SIZE]; + } global; + struct { + u32 iso; + u32 number_audio; + u32 number_midi; + u32 speed; + char names[TX_NAMES_SIZE]; + u32 ac3_caps; + u32 ac3_enable; + } tx; + struct { + u32 iso; + u32 seq_start; + u32 number_audio; + u32 number_midi; + char names[RX_NAMES_SIZE]; + u32 ac3_caps; + u32 ac3_enable; + } rx; + struct { + u32 clock_source; + u32 locked; + u32 rate; + u32 adat_user_data; + } ext_sync; + } buf; + unsigned int quadlets, stream, i; + + if (dice_proc_read_mem(dice, sections, 0, ARRAY_SIZE(sections)) < 0) + return; + snd_iprintf(buffer, "sections:\n"); + for (i = 0; i < ARRAY_SIZE(section_names); ++i) + snd_iprintf(buffer, " %s: offset %u, size %u\n", + section_names[i], + sections[i * 2], sections[i * 2 + 1]); + + quadlets = min_t(u32, sections[1], sizeof(buf.global) / 4); + if (dice_proc_read_mem(dice, &buf.global, sections[0], quadlets) < 0) + return; + snd_iprintf(buffer, "global:\n"); + snd_iprintf(buffer, " owner: %04x:%04x%08x\n", + buf.global.owner_hi >> 16, + buf.global.owner_hi & 0xffff, buf.global.owner_lo); + snd_iprintf(buffer, " notification: %08x\n", buf.global.notification); + dice_proc_fixup_string(buf.global.nick_name, NICK_NAME_SIZE); + snd_iprintf(buffer, " nick name: %s\n", buf.global.nick_name); + snd_iprintf(buffer, " clock select: %s %s\n", + str_from_array(clock_sources, ARRAY_SIZE(clock_sources), + buf.global.clock_select & CLOCK_SOURCE_MASK), + str_from_array(rates, ARRAY_SIZE(rates), + (buf.global.clock_select & CLOCK_RATE_MASK) + >> CLOCK_RATE_SHIFT)); + snd_iprintf(buffer, " enable: %u\n", buf.global.enable); + snd_iprintf(buffer, " status: %slocked %s\n", + buf.global.status & STATUS_SOURCE_LOCKED ? "" : "un", + str_from_array(rates, ARRAY_SIZE(rates), + (buf.global.status & + STATUS_NOMINAL_RATE_MASK) + >> CLOCK_RATE_SHIFT)); + snd_iprintf(buffer, " ext status: %08x\n", buf.global.extended_status); + snd_iprintf(buffer, " sample rate: %u\n", buf.global.sample_rate); + snd_iprintf(buffer, " version: %u.%u.%u.%u\n", + (buf.global.version >> 24) & 0xff, + (buf.global.version >> 16) & 0xff, + (buf.global.version >> 8) & 0xff, + (buf.global.version >> 0) & 0xff); + if (quadlets >= 90) { + snd_iprintf(buffer, " clock caps:"); + for (i = 0; i <= 6; ++i) + if (buf.global.clock_caps & (1 << i)) + snd_iprintf(buffer, " %s", rates[i]); + for (i = 0; i <= 12; ++i) + if (buf.global.clock_caps & (1 << (16 + i))) + snd_iprintf(buffer, " %s", clock_sources[i]); + snd_iprintf(buffer, "\n"); + dice_proc_fixup_string(buf.global.clock_source_names, + CLOCK_SOURCE_NAMES_SIZE); + snd_iprintf(buffer, " clock source names: %s\n", + buf.global.clock_source_names); + } + + if (dice_proc_read_mem(dice, &tx_rx_header, sections[2], 2) < 0) + return; + quadlets = min_t(u32, tx_rx_header.size, sizeof(buf.tx) / 4); + for (stream = 0; stream < tx_rx_header.number; ++stream) { + if (dice_proc_read_mem(dice, &buf.tx, sections[2] + 2 + + stream * tx_rx_header.size, + quadlets) < 0) + break; + snd_iprintf(buffer, "tx %u:\n", stream); + snd_iprintf(buffer, " iso channel: %d\n", (int)buf.tx.iso); + snd_iprintf(buffer, " audio channels: %u\n", + buf.tx.number_audio); + snd_iprintf(buffer, " midi ports: %u\n", buf.tx.number_midi); + snd_iprintf(buffer, " speed: S%u\n", 100u << buf.tx.speed); + if (quadlets >= 68) { + dice_proc_fixup_string(buf.tx.names, TX_NAMES_SIZE); + snd_iprintf(buffer, " names: %s\n", buf.tx.names); + } + if (quadlets >= 70) { + snd_iprintf(buffer, " ac3 caps: %08x\n", + buf.tx.ac3_caps); + snd_iprintf(buffer, " ac3 enable: %08x\n", + buf.tx.ac3_enable); + } + } + + if (dice_proc_read_mem(dice, &tx_rx_header, sections[4], 2) < 0) + return; + quadlets = min_t(u32, tx_rx_header.size, sizeof(buf.rx) / 4); + for (stream = 0; stream < tx_rx_header.number; ++stream) { + if (dice_proc_read_mem(dice, &buf.rx, sections[4] + 2 + + stream * tx_rx_header.size, + quadlets) < 0) + break; + snd_iprintf(buffer, "rx %u:\n", stream); + snd_iprintf(buffer, " iso channel: %d\n", (int)buf.rx.iso); + snd_iprintf(buffer, " sequence start: %u\n", buf.rx.seq_start); + snd_iprintf(buffer, " audio channels: %u\n", + buf.rx.number_audio); + snd_iprintf(buffer, " midi ports: %u\n", buf.rx.number_midi); + if (quadlets >= 68) { + dice_proc_fixup_string(buf.rx.names, RX_NAMES_SIZE); + snd_iprintf(buffer, " names: %s\n", buf.rx.names); + } + if (quadlets >= 70) { + snd_iprintf(buffer, " ac3 caps: %08x\n", + buf.rx.ac3_caps); + snd_iprintf(buffer, " ac3 enable: %08x\n", + buf.rx.ac3_enable); + } + } + + quadlets = min_t(u32, sections[7], sizeof(buf.ext_sync) / 4); + if (quadlets >= 4) { + if (dice_proc_read_mem(dice, &buf.ext_sync, + sections[6], 4) < 0) + return; + snd_iprintf(buffer, "ext status:\n"); + snd_iprintf(buffer, " clock source: %s\n", + str_from_array(clock_sources, + ARRAY_SIZE(clock_sources), + buf.ext_sync.clock_source)); + snd_iprintf(buffer, " locked: %u\n", buf.ext_sync.locked); + snd_iprintf(buffer, " rate: %s\n", + str_from_array(rates, ARRAY_SIZE(rates), + buf.ext_sync.rate)); + snd_iprintf(buffer, " adat user data: "); + if (buf.ext_sync.adat_user_data & ADAT_USER_DATA_NO_DATA) + snd_iprintf(buffer, "-\n"); + else + snd_iprintf(buffer, "%x\n", + buf.ext_sync.adat_user_data); + } +} + +static void dice_create_proc(struct snd_dice *dice) +{ + struct snd_info_entry *entry; + + if (!snd_card_proc_new(dice->card, "dice", &entry)) + snd_info_set_text_ops(entry, dice, dice_proc_read); +} + +static void dice_card_free(struct snd_card *card) +{ + struct snd_dice *dice = card->private_data; + + amdtp_stream_destroy(&dice->rx_stream); + fw_core_remove_address_handler(&dice->notification_handler); + mutex_destroy(&dice->mutex); +} + +#define OUI_WEISS 0x001c6a + +#define DICE_CATEGORY_ID 0x04 +#define WEISS_CATEGORY_ID 0x00 + +static int dice_interface_check(struct fw_unit *unit) +{ + static const int min_values[10] = { + 10, 0x64 / 4, + 10, 0x18 / 4, + 10, 0x18 / 4, + 0, 0, + 0, 0, + }; + struct fw_device *device = fw_parent_device(unit); + struct fw_csr_iterator it; + int key, value, vendor = -1, model = -1, err; + unsigned int category, i; + __be32 pointers[ARRAY_SIZE(min_values)]; + __be32 tx_data[4]; + __be32 version; + + /* + * Check that GUID and unit directory are constructed according to DICE + * rules, i.e., that the specifier ID is the GUID's OUI, and that the + * GUID chip ID consists of the 8-bit category ID, the 10-bit product + * ID, and a 22-bit serial number. + */ + fw_csr_iterator_init(&it, unit->directory); + while (fw_csr_iterator_next(&it, &key, &value)) { + switch (key) { + case CSR_SPECIFIER_ID: + vendor = value; + break; + case CSR_MODEL: + model = value; + break; + } + } + if (vendor == OUI_WEISS) + category = WEISS_CATEGORY_ID; + else + category = DICE_CATEGORY_ID; + if (device->config_rom[3] != ((vendor << 8) | category) || + device->config_rom[4] >> 22 != model) + return -ENODEV; + + /* + * Check that the sub address spaces exist and are located inside the + * private address space. The minimum values are chosen so that all + * minimally required registers are included. + */ + err = snd_fw_transaction(unit, TCODE_READ_BLOCK_REQUEST, + DICE_PRIVATE_SPACE, + pointers, sizeof(pointers), 0); + if (err < 0) + return -ENODEV; + for (i = 0; i < ARRAY_SIZE(pointers); ++i) { + value = be32_to_cpu(pointers[i]); + if (value < min_values[i] || value >= 0x40000) + return -ENODEV; + } + + /* We support playback only. Let capture devices be handled by FFADO. */ + err = snd_fw_transaction(unit, TCODE_READ_BLOCK_REQUEST, + DICE_PRIVATE_SPACE + + be32_to_cpu(pointers[2]) * 4, + tx_data, sizeof(tx_data), 0); + if (err < 0 || (tx_data[0] && tx_data[3])) + return -ENODEV; + + /* + * Check that the implemented DICE driver specification major version + * number matches. + */ + err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST, + DICE_PRIVATE_SPACE + + be32_to_cpu(pointers[0]) * 4 + GLOBAL_VERSION, + &version, 4, 0); + if (err < 0) + return -ENODEV; + if ((version & cpu_to_be32(0xff000000)) != cpu_to_be32(0x01000000)) { + dev_err(&unit->device, + "unknown DICE version: 0x%08x\n", be32_to_cpu(version)); + return -ENODEV; + } + + return 0; +} + +static int highest_supported_mode_rate(struct snd_dice *dice, unsigned int mode) +{ + int i; + + for (i = ARRAY_SIZE(dice_rates) - 1; i >= 0; --i) + if ((dice->clock_caps & (1 << i)) && + rate_index_to_mode(i) == mode) + return i; + + return -1; +} + +static int dice_read_mode_params(struct snd_dice *dice, unsigned int mode) +{ + __be32 values[2]; + int rate_index, err; + + rate_index = highest_supported_mode_rate(dice, mode); + if (rate_index < 0) { + dice->rx_channels[mode] = 0; + dice->rx_midi_ports[mode] = 0; + return 0; + } + + err = dice_change_rate(dice, rate_index << CLOCK_RATE_SHIFT); + if (err < 0) + return err; + + err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST, + rx_address(dice, RX_NUMBER_AUDIO), + values, 2 * 4, 0); + if (err < 0) + return err; + + dice->rx_channels[mode] = be32_to_cpu(values[0]); + dice->rx_midi_ports[mode] = be32_to_cpu(values[1]); + + return 0; +} + +static int dice_read_params(struct snd_dice *dice) +{ + __be32 pointers[6]; + __be32 value; + int mode, err; + + err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST, + DICE_PRIVATE_SPACE, + pointers, sizeof(pointers), 0); + if (err < 0) + return err; + + dice->global_offset = be32_to_cpu(pointers[0]) * 4; + dice->rx_offset = be32_to_cpu(pointers[4]) * 4; + + /* some very old firmwares don't tell about their clock support */ + if (be32_to_cpu(pointers[1]) * 4 >= GLOBAL_CLOCK_CAPABILITIES + 4) { + err = snd_fw_transaction( + dice->unit, TCODE_READ_QUADLET_REQUEST, + global_address(dice, GLOBAL_CLOCK_CAPABILITIES), + &value, 4, 0); + if (err < 0) + return err; + dice->clock_caps = be32_to_cpu(value); + } else { + /* this should be supported by any device */ + dice->clock_caps = CLOCK_CAP_RATE_44100 | + CLOCK_CAP_RATE_48000 | + CLOCK_CAP_SOURCE_ARX1 | + CLOCK_CAP_SOURCE_INTERNAL; + } + + for (mode = 2; mode >= 0; --mode) { + err = dice_read_mode_params(dice, mode); + if (err < 0) + return err; + } + + return 0; +} + +static void dice_card_strings(struct snd_dice *dice) +{ + struct snd_card *card = dice->card; + struct fw_device *dev = fw_parent_device(dice->unit); + char vendor[32], model[32]; + unsigned int i; + int err; + + strcpy(card->driver, "DICE"); + + strcpy(card->shortname, "DICE"); + BUILD_BUG_ON(NICK_NAME_SIZE < sizeof(card->shortname)); + err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST, + global_address(dice, GLOBAL_NICK_NAME), + card->shortname, sizeof(card->shortname), 0); + if (err >= 0) { + /* DICE strings are returned in "always-wrong" endianness */ + BUILD_BUG_ON(sizeof(card->shortname) % 4 != 0); + for (i = 0; i < sizeof(card->shortname); i += 4) + swab32s((u32 *)&card->shortname[i]); + card->shortname[sizeof(card->shortname) - 1] = '\0'; + } + + strcpy(vendor, "?"); + fw_csr_string(dev->config_rom + 5, CSR_VENDOR, vendor, sizeof(vendor)); + strcpy(model, "?"); + fw_csr_string(dice->unit->directory, CSR_MODEL, model, sizeof(model)); + snprintf(card->longname, sizeof(card->longname), + "%s %s (serial %u) at %s, S%d", + vendor, model, dev->config_rom[4] & 0x3fffff, + dev_name(&dice->unit->device), 100 << dev->max_speed); + + strcpy(card->mixername, "DICE"); +} + +static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) +{ + struct snd_card *card; + struct snd_dice *dice; + __be32 clock_sel; + int err; + + err = dice_interface_check(unit); + if (err < 0) + return err; + + err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, + sizeof(*dice), &card); + if (err < 0) + return err; + + dice = card->private_data; + dice->card = card; + spin_lock_init(&dice->lock); + mutex_init(&dice->mutex); + dice->unit = unit; + init_completion(&dice->clock_accepted); + init_waitqueue_head(&dice->hwdep_wait); + + dice->notification_handler.length = 4; + dice->notification_handler.address_callback = dice_notification; + dice->notification_handler.callback_data = dice; + err = fw_core_add_address_handler(&dice->notification_handler, + &fw_high_memory_region); + if (err < 0) + goto err_mutex; + + err = dice_owner_set(dice); + if (err < 0) + goto err_notification_handler; + + err = dice_read_params(dice); + if (err < 0) + goto err_owner; + + err = fw_iso_resources_init(&dice->rx_resources, unit); + if (err < 0) + goto err_owner; + dice->rx_resources.channels_mask = 0x00000000ffffffffuLL; + + err = amdtp_stream_init(&dice->rx_stream, unit, AMDTP_OUT_STREAM, + CIP_BLOCKING); + if (err < 0) + goto err_resources; + + card->private_free = dice_card_free; + + dice_card_strings(dice); + + err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST, + global_address(dice, GLOBAL_CLOCK_SELECT), + &clock_sel, 4, 0); + if (err < 0) + goto error; + clock_sel &= cpu_to_be32(~CLOCK_SOURCE_MASK); + clock_sel |= cpu_to_be32(CLOCK_SOURCE_ARX1); + err = snd_fw_transaction(unit, TCODE_WRITE_QUADLET_REQUEST, + global_address(dice, GLOBAL_CLOCK_SELECT), + &clock_sel, 4, 0); + if (err < 0) + goto error; + + err = dice_create_pcm(dice); + if (err < 0) + goto error; + + err = dice_create_hwdep(dice); + if (err < 0) + goto error; + + dice_create_proc(dice); + + err = snd_card_register(card); + if (err < 0) + goto error; + + dev_set_drvdata(&unit->device, dice); + + return 0; + +err_resources: + fw_iso_resources_destroy(&dice->rx_resources); +err_owner: + dice_owner_clear(dice); +err_notification_handler: + fw_core_remove_address_handler(&dice->notification_handler); +err_mutex: + mutex_destroy(&dice->mutex); +error: + snd_card_free(card); + return err; +} + +static void dice_remove(struct fw_unit *unit) +{ + struct snd_dice *dice = dev_get_drvdata(&unit->device); + + amdtp_stream_pcm_abort(&dice->rx_stream); + + snd_card_disconnect(dice->card); + + mutex_lock(&dice->mutex); + + dice_stream_stop(dice); + dice_owner_clear(dice); + + mutex_unlock(&dice->mutex); + + snd_card_free_when_closed(dice->card); +} + +static void dice_bus_reset(struct fw_unit *unit) +{ + struct snd_dice *dice = dev_get_drvdata(&unit->device); + + /* + * On a bus reset, the DICE firmware disables streaming and then goes + * off contemplating its own navel for hundreds of milliseconds before + * it can react to any of our attempts to reenable streaming. This + * means that we lose synchronization anyway, so we force our streams + * to stop so that the application can restart them in an orderly + * manner. + */ + amdtp_stream_pcm_abort(&dice->rx_stream); + + mutex_lock(&dice->mutex); + + dice->global_enabled = false; + dice_stream_stop_packets(dice); + + dice_owner_update(dice); + + fw_iso_resources_update(&dice->rx_resources); + + mutex_unlock(&dice->mutex); +} + +#define DICE_INTERFACE 0x000001 + +static const struct ieee1394_device_id dice_id_table[] = { + { + .match_flags = IEEE1394_MATCH_VERSION, + .version = DICE_INTERFACE, + }, + { } +}; +MODULE_DEVICE_TABLE(ieee1394, dice_id_table); + +static struct fw_driver dice_driver = { + .driver = { + .owner = THIS_MODULE, + .name = KBUILD_MODNAME, + .bus = &fw_bus_type, + }, + .probe = dice_probe, + .update = dice_bus_reset, + .remove = dice_remove, + .id_table = dice_id_table, +}; + +static int __init alsa_dice_init(void) +{ + return driver_register(&dice_driver.driver); +} + +static void __exit alsa_dice_exit(void) +{ + driver_unregister(&dice_driver.driver); +} + +module_init(alsa_dice_init); +module_exit(alsa_dice_exit); -- cgit v1.2.3 From 7c2d4c0cf5bacb42bc3079e61d299dfaa3dbdde5 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sat, 29 Nov 2014 00:59:13 +0900 Subject: ALSA: dice: Split transaction functionality into a file This commit adds a file with some helper functions for transaction, and move some codes into the file with some arrangements. For Dice chipset, well-known FCP or AV/C commands are not used to control devices. It's achieved by read/write transactions into specific addresses. Dice's address area is split into 5 areas. Each area has its own role. The offset for each area can be got by reading head of the address area. By reading these areas, drivers can get to know device status. By writing these areas, drivers can change device status. Dice has a specific mechanism called as 'notification'. When device status is changed, Dice devices tells the event by sending transaction. This notification is sent to an address which drivers register in advance. But this causes an issue to drivers. To handle the notification, drivers need to allocate its own callback function to the address region in host controller. This region is exclusive. For the other applications, drivers must give a mechanism to read the received notification. For this purpose, Dice driver already implements hwdep interface. Dice chipset doesn't allow drivers to register several addresses. In this reason, when this driver is applied to a device, the other drivers should _not_ try to register its own address to the device. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/dice/Makefile | 2 +- sound/firewire/dice/dice-transaction.c | 387 ++++++++++++++++++++++++++ sound/firewire/dice/dice.c | 487 +++++++-------------------------- sound/firewire/dice/dice.h | 160 +++++++++++ 4 files changed, 653 insertions(+), 383 deletions(-) create mode 100644 sound/firewire/dice/dice-transaction.c create mode 100644 sound/firewire/dice/dice.h (limited to 'sound') diff --git a/sound/firewire/dice/Makefile b/sound/firewire/dice/Makefile index af05d7e9119a..9f473cb7abf1 100644 --- a/sound/firewire/dice/Makefile +++ b/sound/firewire/dice/Makefile @@ -1,2 +1,2 @@ -snd-dice-objs := dice.o +snd-dice-objs := dice-transaction.o dice.o obj-m += snd-dice.o diff --git a/sound/firewire/dice/dice-transaction.c b/sound/firewire/dice/dice-transaction.c new file mode 100644 index 000000000000..a9b98e087dce --- /dev/null +++ b/sound/firewire/dice/dice-transaction.c @@ -0,0 +1,387 @@ +/* + * dice_transaction.c - a part of driver for Dice based devices + * + * Copyright (c) Clemens Ladisch + * Copyright (c) 2014 Takashi Sakamoto + * + * Licensed under the terms of the GNU General Public License, version 2. + */ + +#include "dice.h" + +#define NOTIFICATION_TIMEOUT_MS 100 + +static u64 get_subaddr(struct snd_dice *dice, enum snd_dice_addr_type type, + u64 offset) +{ + switch (type) { + case SND_DICE_ADDR_TYPE_TX: + offset += dice->tx_offset; + break; + case SND_DICE_ADDR_TYPE_RX: + offset += dice->rx_offset; + break; + case SND_DICE_ADDR_TYPE_SYNC: + offset += dice->sync_offset; + break; + case SND_DICE_ADDR_TYPE_RSRV: + offset += dice->rsrv_offset; + break; + case SND_DICE_ADDR_TYPE_GLOBAL: + default: + offset += dice->global_offset; + break; + }; + offset += DICE_PRIVATE_SPACE; + return offset; +} + +int snd_dice_transaction_write(struct snd_dice *dice, + enum snd_dice_addr_type type, + unsigned int offset, void *buf, unsigned int len) +{ + return snd_fw_transaction(dice->unit, + (len == 4) ? TCODE_WRITE_QUADLET_REQUEST : + TCODE_WRITE_BLOCK_REQUEST, + get_subaddr(dice, type, offset), buf, len, 0); +} + +int snd_dice_transaction_read(struct snd_dice *dice, + enum snd_dice_addr_type type, unsigned int offset, + void *buf, unsigned int len) +{ + return snd_fw_transaction(dice->unit, + (len == 4) ? TCODE_READ_QUADLET_REQUEST : + TCODE_READ_BLOCK_REQUEST, + get_subaddr(dice, type, offset), buf, len, 0); +} + +static unsigned int get_clock_info(struct snd_dice *dice, __be32 *info) +{ + return snd_dice_transaction_read_global(dice, GLOBAL_CLOCK_SELECT, + info, 4); +} + +static int set_clock_info(struct snd_dice *dice, + unsigned int rate, unsigned int source) +{ + unsigned int retries = 3; + unsigned int i; + __be32 info; + u32 mask; + u32 clock; + int err; +retry: + err = get_clock_info(dice, &info); + if (err < 0) + goto end; + + clock = be32_to_cpu(info); + if (source != UINT_MAX) { + mask = CLOCK_SOURCE_MASK; + clock &= ~mask; + clock |= source; + } + if (rate != UINT_MAX) { + for (i = 0; i < ARRAY_SIZE(snd_dice_rates); i++) { + if (snd_dice_rates[i] == rate) + break; + } + if (i == ARRAY_SIZE(snd_dice_rates)) { + err = -EINVAL; + goto end; + } + + mask = CLOCK_RATE_MASK; + clock &= ~mask; + clock |= i << CLOCK_RATE_SHIFT; + } + info = cpu_to_be32(clock); + + if (completion_done(&dice->clock_accepted)) + reinit_completion(&dice->clock_accepted); + + err = snd_dice_transaction_write_global(dice, GLOBAL_CLOCK_SELECT, + &info, 4); + if (err < 0) + goto end; + + /* Timeout means it's invalid request, probably bus reset occurred. */ + if (wait_for_completion_timeout(&dice->clock_accepted, + msecs_to_jiffies(NOTIFICATION_TIMEOUT_MS)) == 0) { + if (retries-- == 0) { + err = -ETIMEDOUT; + goto end; + } + + err = snd_dice_transaction_reinit(dice); + if (err < 0) + goto end; + + msleep(500); /* arbitrary */ + goto retry; + } +end: + return err; +} + +int snd_dice_transaction_get_clock_source(struct snd_dice *dice, + unsigned int *source) +{ + __be32 info; + int err; + + err = get_clock_info(dice, &info); + if (err >= 0) + *source = be32_to_cpu(info) & CLOCK_SOURCE_MASK; + + return err; +} +int snd_dice_transaction_set_clock_source(struct snd_dice *dice, + unsigned int source) +{ + return set_clock_info(dice, UINT_MAX, source); +} + +int snd_dice_transaction_get_rate(struct snd_dice *dice, unsigned int *rate) +{ + __be32 info; + unsigned int index; + int err; + + err = get_clock_info(dice, &info); + if (err < 0) + goto end; + + index = (be32_to_cpu(info) & CLOCK_RATE_MASK) >> CLOCK_RATE_SHIFT; + if (index >= SND_DICE_RATES_COUNT) { + err = -ENOSYS; + goto end; + } + + *rate = snd_dice_rates[index]; +end: + return err; +} +int snd_dice_transaction_set_rate(struct snd_dice *dice, unsigned int rate) +{ + return set_clock_info(dice, rate, UINT_MAX); +} + +int snd_dice_transaction_set_enable(struct snd_dice *dice) +{ + __be32 value; + int err = 0; + + if (dice->global_enabled) + goto end; + + value = cpu_to_be32(1); + err = snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST, + get_subaddr(dice, SND_DICE_ADDR_TYPE_GLOBAL, + GLOBAL_ENABLE), + &value, 4, + FW_FIXED_GENERATION | dice->owner_generation); + if (err < 0) + goto end; + + dice->global_enabled = true; +end: + return err; +} + +void snd_dice_transaction_clear_enable(struct snd_dice *dice) +{ + __be32 value; + + value = 0; + snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST, + get_subaddr(dice, SND_DICE_ADDR_TYPE_GLOBAL, + GLOBAL_ENABLE), + &value, 4, FW_QUIET | + FW_FIXED_GENERATION | dice->owner_generation); + + dice->global_enabled = false; +} + +static void dice_notification(struct fw_card *card, struct fw_request *request, + int tcode, int destination, int source, + int generation, unsigned long long offset, + void *data, size_t length, void *callback_data) +{ + struct snd_dice *dice = callback_data; + u32 bits; + unsigned long flags; + + if (tcode != TCODE_WRITE_QUADLET_REQUEST) { + fw_send_response(card, request, RCODE_TYPE_ERROR); + return; + } + if ((offset & 3) != 0) { + fw_send_response(card, request, RCODE_ADDRESS_ERROR); + return; + } + + bits = be32_to_cpup(data); + + spin_lock_irqsave(&dice->lock, flags); + dice->notification_bits |= bits; + spin_unlock_irqrestore(&dice->lock, flags); + + fw_send_response(card, request, RCODE_COMPLETE); + + if (bits & NOTIFY_CLOCK_ACCEPTED) + complete(&dice->clock_accepted); + wake_up(&dice->hwdep_wait); +} + +static int register_notification_address(struct snd_dice *dice, bool retry) +{ + struct fw_device *device = fw_parent_device(dice->unit); + __be64 *buffer; + unsigned int retries; + int err; + + retries = (retry) ? 3 : 0; + + buffer = kmalloc(2 * 8, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + for (;;) { + buffer[0] = cpu_to_be64(OWNER_NO_OWNER); + buffer[1] = cpu_to_be64( + ((u64)device->card->node_id << OWNER_NODE_SHIFT) | + dice->notification_handler.offset); + + dice->owner_generation = device->generation; + smp_rmb(); /* node_id vs. generation */ + err = snd_fw_transaction(dice->unit, TCODE_LOCK_COMPARE_SWAP, + get_subaddr(dice, + SND_DICE_ADDR_TYPE_GLOBAL, + GLOBAL_OWNER), + buffer, 2 * 8, + FW_FIXED_GENERATION | + dice->owner_generation); + if (err == 0) { + /* success */ + if (buffer[0] == cpu_to_be64(OWNER_NO_OWNER)) + break; + /* The address seems to be already registered. */ + if (buffer[0] == buffer[1]) + break; + + dev_err(&dice->unit->device, + "device is already in use\n"); + err = -EBUSY; + } + if (err != -EAGAIN || retries-- > 0) + break; + + msleep(20); + } + + kfree(buffer); + + if (err < 0) + dice->owner_generation = -1; + + return err; +} + +static void unregister_notification_address(struct snd_dice *dice) +{ + struct fw_device *device = fw_parent_device(dice->unit); + __be64 *buffer; + + buffer = kmalloc(2 * 8, GFP_KERNEL); + if (buffer == NULL) + return; + + buffer[0] = cpu_to_be64( + ((u64)device->card->node_id << OWNER_NODE_SHIFT) | + dice->notification_handler.offset); + buffer[1] = cpu_to_be64(OWNER_NO_OWNER); + snd_fw_transaction(dice->unit, TCODE_LOCK_COMPARE_SWAP, + get_subaddr(dice, SND_DICE_ADDR_TYPE_GLOBAL, + GLOBAL_OWNER), + buffer, 2 * 8, FW_QUIET | + FW_FIXED_GENERATION | dice->owner_generation); + + kfree(buffer); + + dice->owner_generation = -1; +} + +void snd_dice_transaction_destroy(struct snd_dice *dice) +{ + struct fw_address_handler *handler = &dice->notification_handler; + + if (handler->callback_data == NULL) + return; + + unregister_notification_address(dice); + + fw_core_remove_address_handler(handler); + handler->callback_data = NULL; +} + +int snd_dice_transaction_reinit(struct snd_dice *dice) +{ + struct fw_address_handler *handler = &dice->notification_handler; + + if (handler->callback_data == NULL) + return -EINVAL; + + return register_notification_address(dice, false); +} + +int snd_dice_transaction_init(struct snd_dice *dice) +{ + struct fw_address_handler *handler = &dice->notification_handler; + __be32 *pointers; + int err; + + /* Use the same way which dice_interface_check() does. */ + pointers = kmalloc(sizeof(__be32) * 10, GFP_KERNEL); + if (pointers == NULL) + return -ENOMEM; + + /* Get offsets for sub-addresses */ + err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST, + DICE_PRIVATE_SPACE, + pointers, sizeof(__be32) * 10, 0); + if (err < 0) + goto end; + + /* Allocation callback in address space over host controller */ + handler->length = 4; + handler->address_callback = dice_notification; + handler->callback_data = dice; + err = fw_core_add_address_handler(handler, &fw_high_memory_region); + if (err < 0) { + handler->callback_data = NULL; + goto end; + } + + /* Register the address space */ + err = register_notification_address(dice, true); + if (err < 0) { + fw_core_remove_address_handler(handler); + handler->callback_data = NULL; + goto end; + } + + dice->global_offset = be32_to_cpu(pointers[0]) * 4; + dice->tx_offset = be32_to_cpu(pointers[2]) * 4; + dice->rx_offset = be32_to_cpu(pointers[4]) * 4; + dice->sync_offset = be32_to_cpu(pointers[6]) * 4; + dice->rsrv_offset = be32_to_cpu(pointers[8]) * 4; + + /* Set up later. */ + if (be32_to_cpu(pointers[1]) * 4 >= GLOBAL_CLOCK_CAPABILITIES + 4) + dice->clock_caps = 1; +end: + kfree(pointers); + return err; +} diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c index d3ec778878af..dd62316ea8b3 100644 --- a/sound/firewire/dice/dice.c +++ b/sound/firewire/dice/dice.c @@ -5,60 +5,13 @@ * Licensed under the terms of the GNU General Public License, version 2. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../amdtp.h" -#include "../iso-resources.h" -#include "../lib.h" -#include "dice-interface.h" - - -struct snd_dice { - struct snd_card *card; - struct fw_unit *unit; - spinlock_t lock; - struct mutex mutex; - unsigned int global_offset; - unsigned int rx_offset; - unsigned int clock_caps; - unsigned int rx_channels[3]; - unsigned int rx_midi_ports[3]; - struct fw_address_handler notification_handler; - int owner_generation; - int dev_lock_count; /* > 0 driver, < 0 userspace */ - bool dev_lock_changed; - bool global_enabled; - struct completion clock_accepted; - wait_queue_head_t hwdep_wait; - u32 notification_bits; - struct fw_iso_resources rx_resources; - struct amdtp_stream rx_stream; -}; +#include "dice.h" MODULE_DESCRIPTION("DICE driver"); MODULE_AUTHOR("Clemens Ladisch "); MODULE_LICENSE("GPL v2"); -static const unsigned int dice_rates[] = { +const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT] = { /* mode 0 */ [0] = 32000, [1] = 44100, @@ -75,8 +28,8 @@ static unsigned int rate_to_index(unsigned int rate) { unsigned int i; - for (i = 0; i < ARRAY_SIZE(dice_rates); ++i) - if (dice_rates[i] == rate) + for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) + if (snd_dice_rates[i] == rate) return i; return 0; @@ -128,192 +81,6 @@ out: spin_unlock_irq(&dice->lock); } -static inline u64 global_address(struct snd_dice *dice, unsigned int offset) -{ - return DICE_PRIVATE_SPACE + dice->global_offset + offset; -} - -/* TODO: rx index */ -static inline u64 rx_address(struct snd_dice *dice, unsigned int offset) -{ - return DICE_PRIVATE_SPACE + dice->rx_offset + offset; -} - -static int dice_owner_set(struct snd_dice *dice) -{ - struct fw_device *device = fw_parent_device(dice->unit); - __be64 *buffer; - int err, errors = 0; - - buffer = kmalloc(2 * 8, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - for (;;) { - buffer[0] = cpu_to_be64(OWNER_NO_OWNER); - buffer[1] = cpu_to_be64( - ((u64)device->card->node_id << OWNER_NODE_SHIFT) | - dice->notification_handler.offset); - - dice->owner_generation = device->generation; - smp_rmb(); /* node_id vs. generation */ - err = snd_fw_transaction(dice->unit, - TCODE_LOCK_COMPARE_SWAP, - global_address(dice, GLOBAL_OWNER), - buffer, 2 * 8, - FW_FIXED_GENERATION | - dice->owner_generation); - - if (err == 0) { - if (buffer[0] != cpu_to_be64(OWNER_NO_OWNER)) { - dev_err(&dice->unit->device, - "device is already in use\n"); - err = -EBUSY; - } - break; - } - if (err != -EAGAIN || ++errors >= 3) - break; - - msleep(20); - } - - kfree(buffer); - - return err; -} - -static int dice_owner_update(struct snd_dice *dice) -{ - struct fw_device *device = fw_parent_device(dice->unit); - __be64 *buffer; - int err; - - if (dice->owner_generation == -1) - return 0; - - buffer = kmalloc(2 * 8, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - buffer[0] = cpu_to_be64(OWNER_NO_OWNER); - buffer[1] = cpu_to_be64( - ((u64)device->card->node_id << OWNER_NODE_SHIFT) | - dice->notification_handler.offset); - - dice->owner_generation = device->generation; - smp_rmb(); /* node_id vs. generation */ - err = snd_fw_transaction(dice->unit, TCODE_LOCK_COMPARE_SWAP, - global_address(dice, GLOBAL_OWNER), - buffer, 2 * 8, - FW_FIXED_GENERATION | dice->owner_generation); - - if (err == 0) { - if (buffer[0] != cpu_to_be64(OWNER_NO_OWNER)) { - dev_err(&dice->unit->device, - "device is already in use\n"); - err = -EBUSY; - } - } else if (err == -EAGAIN) { - err = 0; /* try again later */ - } - - kfree(buffer); - - if (err < 0) - dice->owner_generation = -1; - - return err; -} - -static void dice_owner_clear(struct snd_dice *dice) -{ - struct fw_device *device = fw_parent_device(dice->unit); - __be64 *buffer; - - buffer = kmalloc(2 * 8, GFP_KERNEL); - if (!buffer) - return; - - buffer[0] = cpu_to_be64( - ((u64)device->card->node_id << OWNER_NODE_SHIFT) | - dice->notification_handler.offset); - buffer[1] = cpu_to_be64(OWNER_NO_OWNER); - snd_fw_transaction(dice->unit, TCODE_LOCK_COMPARE_SWAP, - global_address(dice, GLOBAL_OWNER), - buffer, 2 * 8, FW_QUIET | - FW_FIXED_GENERATION | dice->owner_generation); - - kfree(buffer); - - dice->owner_generation = -1; -} - -static int dice_enable_set(struct snd_dice *dice) -{ - __be32 value; - int err; - - value = cpu_to_be32(1); - err = snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST, - global_address(dice, GLOBAL_ENABLE), - &value, 4, - FW_FIXED_GENERATION | dice->owner_generation); - if (err < 0) - return err; - - dice->global_enabled = true; - - return 0; -} - -static void dice_enable_clear(struct snd_dice *dice) -{ - __be32 value; - - if (!dice->global_enabled) - return; - - value = 0; - snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST, - global_address(dice, GLOBAL_ENABLE), - &value, 4, FW_QUIET | - FW_FIXED_GENERATION | dice->owner_generation); - - dice->global_enabled = false; -} - -static void dice_notification(struct fw_card *card, struct fw_request *request, - int tcode, int destination, int source, - int generation, unsigned long long offset, - void *data, size_t length, void *callback_data) -{ - struct snd_dice *dice = callback_data; - u32 bits; - unsigned long flags; - - if (tcode != TCODE_WRITE_QUADLET_REQUEST) { - fw_send_response(card, request, RCODE_TYPE_ERROR); - return; - } - if ((offset & 3) != 0) { - fw_send_response(card, request, RCODE_ADDRESS_ERROR); - return; - } - - bits = be32_to_cpup(data); - - spin_lock_irqsave(&dice->lock, flags); - dice->notification_bits |= bits; - spin_unlock_irqrestore(&dice->lock, flags); - - fw_send_response(card, request, RCODE_COMPLETE); - - if (bits & NOTIFY_CLOCK_ACCEPTED) - complete(&dice->clock_accepted); - wake_up(&dice->hwdep_wait); -} - static int dice_rate_constraint(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { @@ -327,14 +94,14 @@ static int dice_rate_constraint(struct snd_pcm_hw_params *params, }; unsigned int i, mode; - for (i = 0; i < ARRAY_SIZE(dice_rates); ++i) { + for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) { mode = rate_index_to_mode(i); if ((dice->clock_caps & (1 << i)) && snd_interval_test(channels, dice->rx_channels[mode])) { allowed_rates.min = min(allowed_rates.min, - dice_rates[i]); + snd_dice_rates[i]); allowed_rates.max = max(allowed_rates.max, - dice_rates[i]); + snd_dice_rates[i]); } } @@ -354,9 +121,9 @@ static int dice_channels_constraint(struct snd_pcm_hw_params *params, }; unsigned int i, mode; - for (i = 0; i < ARRAY_SIZE(dice_rates); ++i) + for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) if ((dice->clock_caps & (1 << i)) && - snd_interval_test(rate, dice_rates[i])) { + snd_interval_test(rate, snd_dice_rates[i])) { mode = rate_index_to_mode(i); allowed_channels.min = min(allowed_channels.min, dice->rx_channels[mode]); @@ -395,10 +162,10 @@ static int dice_open(struct snd_pcm_substream *substream) runtime->hw = hardware; - for (i = 0; i < ARRAY_SIZE(dice_rates); ++i) + for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) if (dice->clock_caps & (1 << i)) runtime->hw.rates |= - snd_pcm_rate_to_rate_bit(dice_rates[i]); + snd_pcm_rate_to_rate_bit(snd_dice_rates[i]); snd_pcm_limit_hw_rates(runtime); for (i = 0; i < 3; ++i) @@ -453,7 +220,7 @@ static int dice_stream_start_packets(struct snd_dice *dice) if (err < 0) return err; - err = dice_enable_set(dice); + err = snd_dice_transaction_set_enable(dice); if (err < 0) { amdtp_stream_stop(&dice->rx_stream); return err; @@ -475,10 +242,8 @@ static int dice_stream_start(struct snd_dice *dice) goto error; channel = cpu_to_be32(dice->rx_resources.channel); - err = snd_fw_transaction(dice->unit, - TCODE_WRITE_QUADLET_REQUEST, - rx_address(dice, RX_ISOCHRONOUS), - &channel, 4, 0); + err = snd_dice_transaction_write_tx(dice, TX_ISOCHRONOUS, + &channel, 4); if (err < 0) goto err_resources; } @@ -491,8 +256,7 @@ static int dice_stream_start(struct snd_dice *dice) err_rx_channel: channel = cpu_to_be32((u32)-1); - snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST, - rx_address(dice, RX_ISOCHRONOUS), &channel, 4, 0); + snd_dice_transaction_write_rx(dice, RX_ISOCHRONOUS, &channel, 4); err_resources: fw_iso_resources_free(&dice->rx_resources); error: @@ -502,7 +266,7 @@ error: static void dice_stream_stop_packets(struct snd_dice *dice) { if (amdtp_stream_running(&dice->rx_stream)) { - dice_enable_clear(dice); + snd_dice_transaction_clear_enable(dice); amdtp_stream_stop(&dice->rx_stream); } } @@ -517,33 +281,11 @@ static void dice_stream_stop(struct snd_dice *dice) return; channel = cpu_to_be32((u32)-1); - snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST, - rx_address(dice, RX_ISOCHRONOUS), &channel, 4, 0); + snd_dice_transaction_write_rx(dice, RX_ISOCHRONOUS, &channel, 4); fw_iso_resources_free(&dice->rx_resources); } -static int dice_change_rate(struct snd_dice *dice, unsigned int clock_rate) -{ - __be32 value; - int err; - - reinit_completion(&dice->clock_accepted); - - value = cpu_to_be32(clock_rate | CLOCK_SOURCE_ARX1); - err = snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST, - global_address(dice, GLOBAL_CLOCK_SELECT), - &value, 4, 0); - if (err < 0) - return err; - - if (!wait_for_completion_timeout(&dice->clock_accepted, - msecs_to_jiffies(100))) - dev_warn(&dice->unit->device, "clock change timed out\n"); - - return 0; -} - static int dice_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { @@ -561,8 +303,7 @@ static int dice_hw_params(struct snd_pcm_substream *substream, return err; rate = params_rate(hw_params); - rate_index = rate_to_index(rate); - err = dice_change_rate(dice, rate_index << CLOCK_RATE_SHIFT); + err = snd_dice_transaction_set_rate(dice, rate); if (err < 0) return err; @@ -577,6 +318,7 @@ static int dice_hw_params(struct snd_pcm_substream *substream, * be aligned to SYT_INTERVAL. */ channels = params_channels(hw_params); + rate_index = rate_to_index(rate); if (rate_index > 4) { if (channels > AMDTP_MAX_CHANNELS_FOR_PCM / 2) { err = -ENOSYS; @@ -1118,15 +860,6 @@ static void dice_create_proc(struct snd_dice *dice) snd_info_set_text_ops(entry, dice, dice_proc_read); } -static void dice_card_free(struct snd_card *card) -{ - struct snd_dice *dice = card->private_data; - - amdtp_stream_destroy(&dice->rx_stream); - fw_core_remove_address_handler(&dice->notification_handler); - mutex_destroy(&dice->mutex); -} - #define OUI_WEISS 0x001c6a #define DICE_CATEGORY_ID 0x04 @@ -1143,12 +876,17 @@ static int dice_interface_check(struct fw_unit *unit) }; struct fw_device *device = fw_parent_device(unit); struct fw_csr_iterator it; - int key, value, vendor = -1, model = -1, err; + int key, val, vendor = -1, model = -1, err; unsigned int category, i; - __be32 pointers[ARRAY_SIZE(min_values)]; + __be32 *pointers, value; __be32 tx_data[4]; __be32 version; + pointers = kmalloc_array(ARRAY_SIZE(min_values), sizeof(__be32), + GFP_KERNEL); + if (pointers == NULL) + return -ENOMEM; + /* * Check that GUID and unit directory are constructed according to DICE * rules, i.e., that the specifier ID is the GUID's OUI, and that the @@ -1156,13 +894,13 @@ static int dice_interface_check(struct fw_unit *unit) * ID, and a 22-bit serial number. */ fw_csr_iterator_init(&it, unit->directory); - while (fw_csr_iterator_next(&it, &key, &value)) { + while (fw_csr_iterator_next(&it, &key, &val)) { switch (key) { case CSR_SPECIFIER_ID: - vendor = value; + vendor = val; break; case CSR_MODEL: - model = value; + model = val; break; } } @@ -1171,8 +909,10 @@ static int dice_interface_check(struct fw_unit *unit) else category = DICE_CATEGORY_ID; if (device->config_rom[3] != ((vendor << 8) | category) || - device->config_rom[4] >> 22 != model) - return -ENODEV; + device->config_rom[4] >> 22 != model) { + err = -ENODEV; + goto end; + } /* * Check that the sub address spaces exist and are located inside the @@ -1180,14 +920,18 @@ static int dice_interface_check(struct fw_unit *unit) * minimally required registers are included. */ err = snd_fw_transaction(unit, TCODE_READ_BLOCK_REQUEST, - DICE_PRIVATE_SPACE, - pointers, sizeof(pointers), 0); - if (err < 0) - return -ENODEV; - for (i = 0; i < ARRAY_SIZE(pointers); ++i) { + DICE_PRIVATE_SPACE, pointers, + sizeof(__be32) * ARRAY_SIZE(min_values), 0); + if (err < 0) { + err = -ENODEV; + goto end; + } + for (i = 0; i < ARRAY_SIZE(min_values); ++i) { value = be32_to_cpu(pointers[i]); - if (value < min_values[i] || value >= 0x40000) - return -ENODEV; + if (value < min_values[i] || value >= 0x40000) { + err = -ENODEV; + goto end; + } } /* We support playback only. Let capture devices be handled by FFADO. */ @@ -1195,8 +939,10 @@ static int dice_interface_check(struct fw_unit *unit) DICE_PRIVATE_SPACE + be32_to_cpu(pointers[2]) * 4, tx_data, sizeof(tx_data), 0); - if (err < 0 || (tx_data[0] && tx_data[3])) - return -ENODEV; + if (err < 0 || (tx_data[0] && tx_data[3])) { + err = -ENODEV; + goto end; + } /* * Check that the implemented DICE driver specification major version @@ -1206,22 +952,25 @@ static int dice_interface_check(struct fw_unit *unit) DICE_PRIVATE_SPACE + be32_to_cpu(pointers[0]) * 4 + GLOBAL_VERSION, &version, 4, 0); - if (err < 0) - return -ENODEV; + if (err < 0) { + err = -ENODEV; + goto end; + } if ((version & cpu_to_be32(0xff000000)) != cpu_to_be32(0x01000000)) { dev_err(&unit->device, "unknown DICE version: 0x%08x\n", be32_to_cpu(version)); - return -ENODEV; + err = -ENODEV; + goto end; } - - return 0; +end: + return err; } static int highest_supported_mode_rate(struct snd_dice *dice, unsigned int mode) { int i; - for (i = ARRAY_SIZE(dice_rates) - 1; i >= 0; --i) + for (i = ARRAY_SIZE(snd_dice_rates) - 1; i >= 0; --i) if ((dice->clock_caps & (1 << i)) && rate_index_to_mode(i) == mode) return i; @@ -1241,13 +990,12 @@ static int dice_read_mode_params(struct snd_dice *dice, unsigned int mode) return 0; } - err = dice_change_rate(dice, rate_index << CLOCK_RATE_SHIFT); + err = snd_dice_transaction_set_rate(dice, snd_dice_rates[rate_index]); if (err < 0) return err; - err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST, - rx_address(dice, RX_NUMBER_AUDIO), - values, 2 * 4, 0); + err = snd_dice_transaction_read_rx(dice, RX_NUMBER_AUDIO, + values, sizeof(values)); if (err < 0) return err; @@ -1259,25 +1007,14 @@ static int dice_read_mode_params(struct snd_dice *dice, unsigned int mode) static int dice_read_params(struct snd_dice *dice) { - __be32 pointers[6]; __be32 value; int mode, err; - err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST, - DICE_PRIVATE_SPACE, - pointers, sizeof(pointers), 0); - if (err < 0) - return err; - - dice->global_offset = be32_to_cpu(pointers[0]) * 4; - dice->rx_offset = be32_to_cpu(pointers[4]) * 4; - /* some very old firmwares don't tell about their clock support */ - if (be32_to_cpu(pointers[1]) * 4 >= GLOBAL_CLOCK_CAPABILITIES + 4) { - err = snd_fw_transaction( - dice->unit, TCODE_READ_QUADLET_REQUEST, - global_address(dice, GLOBAL_CLOCK_CAPABILITIES), - &value, 4, 0); + if (dice->clock_caps > 0) { + err = snd_dice_transaction_read_global(dice, + GLOBAL_CLOCK_CAPABILITIES, + &value, 4); if (err < 0) return err; dice->clock_caps = be32_to_cpu(value); @@ -1310,9 +1047,9 @@ static void dice_card_strings(struct snd_dice *dice) strcpy(card->shortname, "DICE"); BUILD_BUG_ON(NICK_NAME_SIZE < sizeof(card->shortname)); - err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST, - global_address(dice, GLOBAL_NICK_NAME), - card->shortname, sizeof(card->shortname), 0); + err = snd_dice_transaction_read_global(dice, GLOBAL_NICK_NAME, + card->shortname, + sizeof(card->shortname)); if (err >= 0) { /* DICE strings are returned in "always-wrong" endianness */ BUILD_BUG_ON(sizeof(card->shortname) % 4 != 0); @@ -1333,70 +1070,50 @@ static void dice_card_strings(struct snd_dice *dice) strcpy(card->mixername, "DICE"); } +static void dice_card_free(struct snd_card *card) +{ + struct snd_dice *dice = card->private_data; + + snd_dice_transaction_destroy(dice); + mutex_destroy(&dice->mutex); +} + static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) { struct snd_card *card; struct snd_dice *dice; - __be32 clock_sel; int err; err = dice_interface_check(unit); if (err < 0) - return err; + goto end; err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, sizeof(*dice), &card); if (err < 0) - return err; + goto end; dice = card->private_data; dice->card = card; + dice->unit = unit; + card->private_free = dice_card_free; + spin_lock_init(&dice->lock); mutex_init(&dice->mutex); - dice->unit = unit; init_completion(&dice->clock_accepted); init_waitqueue_head(&dice->hwdep_wait); - dice->notification_handler.length = 4; - dice->notification_handler.address_callback = dice_notification; - dice->notification_handler.callback_data = dice; - err = fw_core_add_address_handler(&dice->notification_handler, - &fw_high_memory_region); - if (err < 0) - goto err_mutex; - - err = dice_owner_set(dice); + err = snd_dice_transaction_init(dice); if (err < 0) - goto err_notification_handler; + goto error; err = dice_read_params(dice); if (err < 0) - goto err_owner; - - err = fw_iso_resources_init(&dice->rx_resources, unit); - if (err < 0) - goto err_owner; - dice->rx_resources.channels_mask = 0x00000000ffffffffuLL; - - err = amdtp_stream_init(&dice->rx_stream, unit, AMDTP_OUT_STREAM, - CIP_BLOCKING); - if (err < 0) - goto err_resources; - - card->private_free = dice_card_free; + goto error; dice_card_strings(dice); - err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST, - global_address(dice, GLOBAL_CLOCK_SELECT), - &clock_sel, 4, 0); - if (err < 0) - goto error; - clock_sel &= cpu_to_be32(~CLOCK_SOURCE_MASK); - clock_sel |= cpu_to_be32(CLOCK_SOURCE_ARX1); - err = snd_fw_transaction(unit, TCODE_WRITE_QUADLET_REQUEST, - global_address(dice, GLOBAL_CLOCK_SELECT), - &clock_sel, 4, 0); + err = snd_dice_transaction_set_clock_source(dice, CLOCK_SOURCE_ARX1); if (err < 0) goto error; @@ -1410,22 +1127,28 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) dice_create_proc(dice); - err = snd_card_register(card); + err = fw_iso_resources_init(&dice->rx_resources, unit); if (err < 0) goto error; + dice->rx_resources.channels_mask = 0x00000000ffffffffuLL; - dev_set_drvdata(&unit->device, dice); + err = amdtp_stream_init(&dice->rx_stream, unit, AMDTP_OUT_STREAM, + CIP_BLOCKING); + if (err < 0) { + fw_iso_resources_destroy(&dice->rx_resources); + goto error; + } - return 0; + err = snd_card_register(card); + if (err < 0) { + amdtp_stream_destroy(&dice->rx_stream); + fw_iso_resources_destroy(&dice->rx_resources); + goto error; + } -err_resources: - fw_iso_resources_destroy(&dice->rx_resources); -err_owner: - dice_owner_clear(dice); -err_notification_handler: - fw_core_remove_address_handler(&dice->notification_handler); -err_mutex: - mutex_destroy(&dice->mutex); + dev_set_drvdata(&unit->device, dice); +end: + return err; error: snd_card_free(card); return err; @@ -1442,7 +1165,6 @@ static void dice_remove(struct fw_unit *unit) mutex_lock(&dice->mutex); dice_stream_stop(dice); - dice_owner_clear(dice); mutex_unlock(&dice->mutex); @@ -1453,6 +1175,9 @@ static void dice_bus_reset(struct fw_unit *unit) { struct snd_dice *dice = dev_get_drvdata(&unit->device); + /* The handler address register becomes initialized. */ + snd_dice_transaction_reinit(dice); + /* * On a bus reset, the DICE firmware disables streaming and then goes * off contemplating its own navel for hundreds of milliseconds before @@ -1466,10 +1191,8 @@ static void dice_bus_reset(struct fw_unit *unit) mutex_lock(&dice->mutex); dice->global_enabled = false; - dice_stream_stop_packets(dice); - - dice_owner_update(dice); + dice_stream_stop_packets(dice); fw_iso_resources_update(&dice->rx_resources); mutex_unlock(&dice->mutex); diff --git a/sound/firewire/dice/dice.h b/sound/firewire/dice/dice.h new file mode 100644 index 000000000000..c756e62ea4ec --- /dev/null +++ b/sound/firewire/dice/dice.h @@ -0,0 +1,160 @@ +/* + * dice.h - a part of driver for Dice based devices + * + * Copyright (c) Clemens Ladisch + * Copyright (c) 2014 Takashi Sakamoto + * + * Licensed under the terms of the GNU General Public License, version 2. + */ + +#ifndef SOUND_DICE_H_INCLUDED +#define SOUND_DICE_H_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../amdtp.h" +#include "../iso-resources.h" +#include "../lib.h" +#include "dice-interface.h" + +struct snd_dice { + struct snd_card *card; + struct fw_unit *unit; + spinlock_t lock; + struct mutex mutex; + + /* Offsets for sub-addresses */ + unsigned int global_offset; + unsigned int rx_offset; + unsigned int tx_offset; + unsigned int sync_offset; + unsigned int rsrv_offset; + + unsigned int clock_caps; + unsigned int rx_channels[3]; + unsigned int rx_midi_ports[3]; + struct fw_address_handler notification_handler; + int owner_generation; + int dev_lock_count; /* > 0 driver, < 0 userspace */ + bool dev_lock_changed; + bool global_enabled; + struct completion clock_accepted; + wait_queue_head_t hwdep_wait; + u32 notification_bits; + struct fw_iso_resources rx_resources; + struct amdtp_stream rx_stream; +}; + +enum snd_dice_addr_type { + SND_DICE_ADDR_TYPE_PRIVATE, + SND_DICE_ADDR_TYPE_GLOBAL, + SND_DICE_ADDR_TYPE_TX, + SND_DICE_ADDR_TYPE_RX, + SND_DICE_ADDR_TYPE_SYNC, + SND_DICE_ADDR_TYPE_RSRV, +}; + +int snd_dice_transaction_write(struct snd_dice *dice, + enum snd_dice_addr_type type, + unsigned int offset, + void *buf, unsigned int len); +int snd_dice_transaction_read(struct snd_dice *dice, + enum snd_dice_addr_type type, unsigned int offset, + void *buf, unsigned int len); + +static inline int snd_dice_transaction_write_global(struct snd_dice *dice, + unsigned int offset, + void *buf, unsigned int len) +{ + return snd_dice_transaction_write(dice, + SND_DICE_ADDR_TYPE_GLOBAL, offset, + buf, len); +} +static inline int snd_dice_transaction_read_global(struct snd_dice *dice, + unsigned int offset, + void *buf, unsigned int len) +{ + return snd_dice_transaction_read(dice, + SND_DICE_ADDR_TYPE_GLOBAL, offset, + buf, len); +} +static inline int snd_dice_transaction_write_tx(struct snd_dice *dice, + unsigned int offset, + void *buf, unsigned int len) +{ + return snd_dice_transaction_write(dice, SND_DICE_ADDR_TYPE_TX, offset, + buf, len); +} +static inline int snd_dice_transaction_read_tx(struct snd_dice *dice, + unsigned int offset, + void *buf, unsigned int len) +{ + return snd_dice_transaction_read(dice, SND_DICE_ADDR_TYPE_TX, offset, + buf, len); +} +static inline int snd_dice_transaction_write_rx(struct snd_dice *dice, + unsigned int offset, + void *buf, unsigned int len) +{ + return snd_dice_transaction_write(dice, SND_DICE_ADDR_TYPE_RX, offset, + buf, len); +} +static inline int snd_dice_transaction_read_rx(struct snd_dice *dice, + unsigned int offset, + void *buf, unsigned int len) +{ + return snd_dice_transaction_read(dice, SND_DICE_ADDR_TYPE_RX, offset, + buf, len); +} +static inline int snd_dice_transaction_write_sync(struct snd_dice *dice, + unsigned int offset, + void *buf, unsigned int len) +{ + return snd_dice_transaction_write(dice, SND_DICE_ADDR_TYPE_SYNC, offset, + buf, len); +} +static inline int snd_dice_transaction_read_sync(struct snd_dice *dice, + unsigned int offset, + void *buf, unsigned int len) +{ + return snd_dice_transaction_read(dice, SND_DICE_ADDR_TYPE_SYNC, offset, + buf, len); +} + +int snd_dice_transaction_set_clock_source(struct snd_dice *dice, + unsigned int source); +int snd_dice_transaction_get_clock_source(struct snd_dice *dice, + unsigned int *source); +int snd_dice_transaction_set_rate(struct snd_dice *dice, unsigned int rate); +int snd_dice_transaction_get_rate(struct snd_dice *dice, unsigned int *rate); +int snd_dice_transaction_set_enable(struct snd_dice *dice); +void snd_dice_transaction_clear_enable(struct snd_dice *dice); +int snd_dice_transaction_init(struct snd_dice *dice); +int snd_dice_transaction_reinit(struct snd_dice *dice); +void snd_dice_transaction_destroy(struct snd_dice *dice); + +#define SND_DICE_RATES_COUNT 7 +extern const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT]; + +#endif -- cgit v1.2.3 From 6eb6c81eee2a6270b39ca02a446f3ccece24b6f8 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sat, 29 Nov 2014 00:59:14 +0900 Subject: ALSA: dice: Split stream functionality into a file This commit adds a file with some helper functions for streaming, and move some codes into the file with some arrangements. Well-known CMP is not used to start/stop streams for Dice chipset. It's achieved by writing to specific address. We call this way as 'enable'. When devices are 'enabled', streaming starts in registered isochronous channel. Some helper functions are already implemented in previous commit. Basically, the stream is compliant to IEC 61883-6, so-called as AMDTP. But Dice has a specific quirk, so called-as 'Dual Wire'. This quirk is applied at 176.4/192.0kHz. In this mode, each packet includes double number of events than number in the specification, and stream runs at a half of sampling rate. There is another quirk at bus reset. Dice chipset handles drivers' request but don't re-enable streaming. So stream should be stopped. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/dice/Makefile | 2 +- sound/firewire/dice/dice-stream.c | 206 ++++++++++++++++++++++++++ sound/firewire/dice/dice.c | 299 +++++++++----------------------------- sound/firewire/dice/dice.h | 14 ++ 4 files changed, 288 insertions(+), 233 deletions(-) create mode 100644 sound/firewire/dice/dice-stream.c (limited to 'sound') diff --git a/sound/firewire/dice/Makefile b/sound/firewire/dice/Makefile index 9f473cb7abf1..867864ca514f 100644 --- a/sound/firewire/dice/Makefile +++ b/sound/firewire/dice/Makefile @@ -1,2 +1,2 @@ -snd-dice-objs := dice-transaction.o dice.o +snd-dice-objs := dice-transaction.o dice-stream.o dice.o obj-m += snd-dice.o diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c new file mode 100644 index 000000000000..c25b9fb39d1f --- /dev/null +++ b/sound/firewire/dice/dice-stream.c @@ -0,0 +1,206 @@ +/* + * dice_stream.c - a part of driver for DICE based devices + * + * Copyright (c) Clemens Ladisch + * Copyright (c) 2014 Takashi Sakamoto + * + * Licensed under the terms of the GNU General Public License, version 2. + */ + +#include "dice.h" + +const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT] = { + /* mode 0 */ + [0] = 32000, + [1] = 44100, + [2] = 48000, + /* mode 1 */ + [3] = 88200, + [4] = 96000, + /* mode 2 */ + [5] = 176400, + [6] = 192000, +}; + +int snd_dice_stream_get_rate_mode(struct snd_dice *dice, unsigned int rate, + unsigned int *mode) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(snd_dice_rates); i++) { + if (!(dice->clock_caps & BIT(i))) + continue; + if (snd_dice_rates[i] != rate) + continue; + + *mode = (i - 1) / 2; + return 0; + } + return -EINVAL; +} + +int snd_dice_stream_start_packets(struct snd_dice *dice) +{ + int err; + + if (amdtp_stream_running(&dice->rx_stream)) + return 0; + + err = amdtp_stream_start(&dice->rx_stream, dice->rx_resources.channel, + fw_parent_device(dice->unit)->max_speed); + if (err < 0) + return err; + + err = snd_dice_transaction_set_enable(dice); + if (err < 0) { + amdtp_stream_stop(&dice->rx_stream); + return err; + } + + return 0; +} + +int snd_dice_stream_start(struct snd_dice *dice) +{ + __be32 channel; + int err; + + if (!dice->rx_resources.allocated) { + err = fw_iso_resources_allocate(&dice->rx_resources, + amdtp_stream_get_max_payload(&dice->rx_stream), + fw_parent_device(dice->unit)->max_speed); + if (err < 0) + goto error; + + channel = cpu_to_be32(dice->rx_resources.channel); + err = snd_dice_transaction_write_tx(dice, RX_ISOCHRONOUS, + &channel, 4); + if (err < 0) + goto err_resources; + } + + err = snd_dice_stream_start_packets(dice); + if (err < 0) + goto err_rx_channel; + + return 0; + +err_rx_channel: + channel = cpu_to_be32((u32)-1); + snd_dice_transaction_write_rx(dice, RX_ISOCHRONOUS, &channel, 4); +err_resources: + fw_iso_resources_free(&dice->rx_resources); +error: + return err; +} + +void snd_dice_stream_stop_packets(struct snd_dice *dice) +{ + if (amdtp_stream_running(&dice->rx_stream)) { + snd_dice_transaction_clear_enable(dice); + amdtp_stream_stop(&dice->rx_stream); + } +} + +void snd_dice_stream_stop(struct snd_dice *dice) +{ + __be32 channel; + + snd_dice_stream_stop_packets(dice); + + if (!dice->rx_resources.allocated) + return; + + channel = cpu_to_be32((u32)-1); + snd_dice_transaction_write_rx(dice, RX_ISOCHRONOUS, &channel, 4); + + fw_iso_resources_free(&dice->rx_resources); +} + +int snd_dice_stream_init(struct snd_dice *dice) +{ + int err; + + err = fw_iso_resources_init(&dice->rx_resources, dice->unit); + if (err < 0) + goto end; + dice->rx_resources.channels_mask = 0x00000000ffffffffuLL; + + err = amdtp_stream_init(&dice->rx_stream, dice->unit, AMDTP_OUT_STREAM, + CIP_BLOCKING); + if (err < 0) + goto error; + + err = snd_dice_transaction_set_clock_source(dice, CLOCK_SOURCE_ARX1); + if (err < 0) + goto error; +end: + return err; +error: + amdtp_stream_destroy(&dice->rx_stream); + fw_iso_resources_destroy(&dice->rx_resources); + return err; +} + +void snd_dice_stream_destroy(struct snd_dice *dice) +{ + amdtp_stream_pcm_abort(&dice->rx_stream); + snd_dice_stream_stop(dice); + amdtp_stream_destroy(&dice->rx_stream); + fw_iso_resources_destroy(&dice->rx_resources); +} + +void snd_dice_stream_update(struct snd_dice *dice) +{ + /* + * On a bus reset, the DICE firmware disables streaming and then goes + * off contemplating its own navel for hundreds of milliseconds before + * it can react to any of our attempts to reenable streaming. This + * means that we lose synchronization anyway, so we force our streams + * to stop so that the application can restart them in an orderly + * manner. + */ + dice->global_enabled = false; + + amdtp_stream_pcm_abort(&dice->rx_stream); + snd_dice_stream_stop_packets(dice); + fw_iso_resources_update(&dice->rx_resources); +} + +static void dice_lock_changed(struct snd_dice *dice) +{ + dice->dev_lock_changed = true; + wake_up(&dice->hwdep_wait); +} + +int snd_dice_stream_lock_try(struct snd_dice *dice) +{ + int err; + + spin_lock_irq(&dice->lock); + + if (dice->dev_lock_count < 0) { + err = -EBUSY; + goto out; + } + + if (dice->dev_lock_count++ == 0) + dice_lock_changed(dice); + err = 0; +out: + spin_unlock_irq(&dice->lock); + return err; +} + +void snd_dice_stream_lock_release(struct snd_dice *dice) +{ + spin_lock_irq(&dice->lock); + + if (WARN_ON(dice->dev_lock_count <= 0)) + goto out; + + if (--dice->dev_lock_count == 0) + dice_lock_changed(dice); +out: + spin_unlock_irq(&dice->lock); +} diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c index dd62316ea8b3..e032b1caa776 100644 --- a/sound/firewire/dice/dice.c +++ b/sound/firewire/dice/dice.c @@ -11,127 +11,62 @@ MODULE_DESCRIPTION("DICE driver"); MODULE_AUTHOR("Clemens Ladisch "); MODULE_LICENSE("GPL v2"); -const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT] = { - /* mode 0 */ - [0] = 32000, - [1] = 44100, - [2] = 48000, - /* mode 1 */ - [3] = 88200, - [4] = 96000, - /* mode 2 */ - [5] = 176400, - [6] = 192000, -}; - -static unsigned int rate_to_index(unsigned int rate) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) - if (snd_dice_rates[i] == rate) - return i; - - return 0; -} - -static unsigned int rate_index_to_mode(unsigned int rate_index) -{ - return ((int)rate_index - 1) / 2; -} - -static void dice_lock_changed(struct snd_dice *dice) -{ - dice->dev_lock_changed = true; - wake_up(&dice->hwdep_wait); -} - -static int dice_try_lock(struct snd_dice *dice) -{ - int err; - - spin_lock_irq(&dice->lock); - - if (dice->dev_lock_count < 0) { - err = -EBUSY; - goto out; - } - - if (dice->dev_lock_count++ == 0) - dice_lock_changed(dice); - err = 0; - -out: - spin_unlock_irq(&dice->lock); - - return err; -} - -static void dice_unlock(struct snd_dice *dice) -{ - spin_lock_irq(&dice->lock); - - if (WARN_ON(dice->dev_lock_count <= 0)) - goto out; - - if (--dice->dev_lock_count == 0) - dice_lock_changed(dice); - -out: - spin_unlock_irq(&dice->lock); -} - static int dice_rate_constraint(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { struct snd_dice *dice = rule->private; - const struct snd_interval *channels = + + const struct snd_interval *c = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_interval *rate = + struct snd_interval *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval allowed_rates = { + struct snd_interval rates = { .min = UINT_MAX, .max = 0, .integer = 1 }; - unsigned int i, mode; + unsigned int i, rate, mode, *pcm_channels = dice->rx_channels; for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) { - mode = rate_index_to_mode(i); - if ((dice->clock_caps & (1 << i)) && - snd_interval_test(channels, dice->rx_channels[mode])) { - allowed_rates.min = min(allowed_rates.min, - snd_dice_rates[i]); - allowed_rates.max = max(allowed_rates.max, - snd_dice_rates[i]); - } + rate = snd_dice_rates[i]; + if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0) + continue; + + if (!snd_interval_test(c, pcm_channels[mode])) + continue; + + rates.min = min(rates.min, rate); + rates.max = max(rates.max, rate); } - return snd_interval_refine(rate, &allowed_rates); + return snd_interval_refine(r, &rates); } static int dice_channels_constraint(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { struct snd_dice *dice = rule->private; - const struct snd_interval *rate = + + const struct snd_interval *r = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *channels = + struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_interval allowed_channels = { + struct snd_interval channels = { .min = UINT_MAX, .max = 0, .integer = 1 }; - unsigned int i, mode; + unsigned int i, rate, mode, *pcm_channels = dice->rx_channels; - for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) - if ((dice->clock_caps & (1 << i)) && - snd_interval_test(rate, snd_dice_rates[i])) { - mode = rate_index_to_mode(i); - allowed_channels.min = min(allowed_channels.min, - dice->rx_channels[mode]); - allowed_channels.max = max(allowed_channels.max, - dice->rx_channels[mode]); - } + for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) { + rate = snd_dice_rates[i]; + if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0) + continue; - return snd_interval_refine(channels, &allowed_channels); + if (!snd_interval_test(r, rate)) + continue; + + channels.min = min(channels.min, pcm_channels[mode]); + channels.max = max(channels.max, pcm_channels[mode]); + } + + return snd_interval_refine(c, &channels); } static int dice_open(struct snd_pcm_substream *substream) @@ -156,7 +91,7 @@ static int dice_open(struct snd_pcm_substream *substream) unsigned int i; int err; - err = dice_try_lock(dice); + err = snd_dice_stream_lock_try(dice); if (err < 0) goto error; @@ -194,7 +129,7 @@ static int dice_open(struct snd_pcm_substream *substream) return 0; err_lock: - dice_unlock(dice); + snd_dice_stream_lock_release(dice); error: return err; } @@ -203,98 +138,20 @@ static int dice_close(struct snd_pcm_substream *substream) { struct snd_dice *dice = substream->private_data; - dice_unlock(dice); + snd_dice_stream_lock_release(dice); return 0; } -static int dice_stream_start_packets(struct snd_dice *dice) -{ - int err; - - if (amdtp_stream_running(&dice->rx_stream)) - return 0; - - err = amdtp_stream_start(&dice->rx_stream, dice->rx_resources.channel, - fw_parent_device(dice->unit)->max_speed); - if (err < 0) - return err; - - err = snd_dice_transaction_set_enable(dice); - if (err < 0) { - amdtp_stream_stop(&dice->rx_stream); - return err; - } - - return 0; -} - -static int dice_stream_start(struct snd_dice *dice) -{ - __be32 channel; - int err; - - if (!dice->rx_resources.allocated) { - err = fw_iso_resources_allocate(&dice->rx_resources, - amdtp_stream_get_max_payload(&dice->rx_stream), - fw_parent_device(dice->unit)->max_speed); - if (err < 0) - goto error; - - channel = cpu_to_be32(dice->rx_resources.channel); - err = snd_dice_transaction_write_tx(dice, TX_ISOCHRONOUS, - &channel, 4); - if (err < 0) - goto err_resources; - } - - err = dice_stream_start_packets(dice); - if (err < 0) - goto err_rx_channel; - - return 0; - -err_rx_channel: - channel = cpu_to_be32((u32)-1); - snd_dice_transaction_write_rx(dice, RX_ISOCHRONOUS, &channel, 4); -err_resources: - fw_iso_resources_free(&dice->rx_resources); -error: - return err; -} - -static void dice_stream_stop_packets(struct snd_dice *dice) -{ - if (amdtp_stream_running(&dice->rx_stream)) { - snd_dice_transaction_clear_enable(dice); - amdtp_stream_stop(&dice->rx_stream); - } -} - -static void dice_stream_stop(struct snd_dice *dice) -{ - __be32 channel; - - dice_stream_stop_packets(dice); - - if (!dice->rx_resources.allocated) - return; - - channel = cpu_to_be32((u32)-1); - snd_dice_transaction_write_rx(dice, RX_ISOCHRONOUS, &channel, 4); - - fw_iso_resources_free(&dice->rx_resources); -} - static int dice_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { struct snd_dice *dice = substream->private_data; - unsigned int rate_index, mode, rate, channels, i; + unsigned int mode, rate, channels, i; int err; mutex_lock(&dice->mutex); - dice_stream_stop(dice); + snd_dice_stream_stop(dice); mutex_unlock(&dice->mutex); err = snd_pcm_lib_alloc_vmalloc_buffer(substream, @@ -307,6 +164,10 @@ static int dice_hw_params(struct snd_pcm_substream *substream, if (err < 0) return err; + err = snd_dice_stream_get_rate_mode(dice, rate, &mode); + if (err < 0) + return err; + /* * At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in * one data block of AMDTP packet. Thus sampling transfer frequency is @@ -318,8 +179,7 @@ static int dice_hw_params(struct snd_pcm_substream *substream, * be aligned to SYT_INTERVAL. */ channels = params_channels(hw_params); - rate_index = rate_to_index(rate); - if (rate_index > 4) { + if (mode > 1) { if (channels > AMDTP_MAX_CHANNELS_FOR_PCM / 2) { err = -ENOSYS; return err; @@ -332,10 +192,9 @@ static int dice_hw_params(struct snd_pcm_substream *substream, dice->rx_stream.double_pcm_frames = false; } - mode = rate_index_to_mode(rate_index); amdtp_stream_set_parameters(&dice->rx_stream, rate, channels, dice->rx_midi_ports[mode]); - if (rate_index > 4) { + if (mode > 4) { channels /= 2; for (i = 0; i < channels; i++) { @@ -355,7 +214,7 @@ static int dice_hw_free(struct snd_pcm_substream *substream) struct snd_dice *dice = substream->private_data; mutex_lock(&dice->mutex); - dice_stream_stop(dice); + snd_dice_stream_stop(dice); mutex_unlock(&dice->mutex); return snd_pcm_lib_free_vmalloc_buffer(substream); @@ -369,9 +228,9 @@ static int dice_prepare(struct snd_pcm_substream *substream) mutex_lock(&dice->mutex); if (amdtp_streaming_error(&dice->rx_stream)) - dice_stream_stop_packets(dice); + snd_dice_stream_stop_packets(dice); - err = dice_stream_start(dice); + err = snd_dice_stream_start(dice); if (err < 0) { mutex_unlock(&dice->mutex); return err; @@ -966,31 +825,37 @@ end: return err; } -static int highest_supported_mode_rate(struct snd_dice *dice, unsigned int mode) +static int highest_supported_mode_rate(struct snd_dice *dice, + unsigned int mode, unsigned int *rate) { - int i; + unsigned int i, m; - for (i = ARRAY_SIZE(snd_dice_rates) - 1; i >= 0; --i) - if ((dice->clock_caps & (1 << i)) && - rate_index_to_mode(i) == mode) - return i; + for (i = ARRAY_SIZE(snd_dice_rates); i > 0; i--) { + *rate = snd_dice_rates[i - 1]; + if (snd_dice_stream_get_rate_mode(dice, *rate, &m) < 0) + continue; + if (mode == m) + break; + } + if (i == 0) + return -EINVAL; - return -1; + return 0; } static int dice_read_mode_params(struct snd_dice *dice, unsigned int mode) { __be32 values[2]; - int rate_index, err; + unsigned int rate; + int err; - rate_index = highest_supported_mode_rate(dice, mode); - if (rate_index < 0) { + if (highest_supported_mode_rate(dice, mode, &rate) < 0) { dice->rx_channels[mode] = 0; dice->rx_midi_ports[mode] = 0; return 0; } - err = snd_dice_transaction_set_rate(dice, snd_dice_rates[rate_index]); + err = snd_dice_transaction_set_rate(dice, rate); if (err < 0) return err; @@ -1113,10 +978,6 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) dice_card_strings(dice); - err = snd_dice_transaction_set_clock_source(dice, CLOCK_SOURCE_ARX1); - if (err < 0) - goto error; - err = dice_create_pcm(dice); if (err < 0) goto error; @@ -1127,22 +988,13 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) dice_create_proc(dice); - err = fw_iso_resources_init(&dice->rx_resources, unit); + err = snd_dice_stream_init(dice); if (err < 0) goto error; - dice->rx_resources.channels_mask = 0x00000000ffffffffuLL; - - err = amdtp_stream_init(&dice->rx_stream, unit, AMDTP_OUT_STREAM, - CIP_BLOCKING); - if (err < 0) { - fw_iso_resources_destroy(&dice->rx_resources); - goto error; - } err = snd_card_register(card); if (err < 0) { - amdtp_stream_destroy(&dice->rx_stream); - fw_iso_resources_destroy(&dice->rx_resources); + snd_dice_stream_destroy(dice); goto error; } @@ -1158,13 +1010,11 @@ static void dice_remove(struct fw_unit *unit) { struct snd_dice *dice = dev_get_drvdata(&unit->device); - amdtp_stream_pcm_abort(&dice->rx_stream); - snd_card_disconnect(dice->card); mutex_lock(&dice->mutex); - dice_stream_stop(dice); + snd_dice_stream_destroy(dice); mutex_unlock(&dice->mutex); @@ -1178,23 +1028,8 @@ static void dice_bus_reset(struct fw_unit *unit) /* The handler address register becomes initialized. */ snd_dice_transaction_reinit(dice); - /* - * On a bus reset, the DICE firmware disables streaming and then goes - * off contemplating its own navel for hundreds of milliseconds before - * it can react to any of our attempts to reenable streaming. This - * means that we lose synchronization anyway, so we force our streams - * to stop so that the application can restart them in an orderly - * manner. - */ - amdtp_stream_pcm_abort(&dice->rx_stream); - mutex_lock(&dice->mutex); - - dice->global_enabled = false; - - dice_stream_stop_packets(dice); - fw_iso_resources_update(&dice->rx_resources); - + snd_dice_stream_update(dice); mutex_unlock(&dice->mutex); } diff --git a/sound/firewire/dice/dice.h b/sound/firewire/dice/dice.h index c756e62ea4ec..ca4090d881e6 100644 --- a/sound/firewire/dice/dice.h +++ b/sound/firewire/dice/dice.h @@ -157,4 +157,18 @@ void snd_dice_transaction_destroy(struct snd_dice *dice); #define SND_DICE_RATES_COUNT 7 extern const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT]; +int snd_dice_stream_get_rate_mode(struct snd_dice *dice, + unsigned int rate, unsigned int *mode); + +int snd_dice_stream_start_packets(struct snd_dice *dice); +int snd_dice_stream_start(struct snd_dice *dice); +void snd_dice_stream_stop_packets(struct snd_dice *dice); +void snd_dice_stream_stop(struct snd_dice *dice); +int snd_dice_stream_init(struct snd_dice *dice); +void snd_dice_stream_destroy(struct snd_dice *dice); +void snd_dice_stream_update(struct snd_dice *dice); + +int snd_dice_stream_lock_try(struct snd_dice *dice); +void snd_dice_stream_lock_release(struct snd_dice *dice); + #endif -- cgit v1.2.3 From c50fb91f53626e3bdae3ffebfee586786f970f7c Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sat, 29 Nov 2014 00:59:15 +0900 Subject: ALSA: dice: Split PCM functionality into a file This commit adds a file and move some codes related to PCM functionality. Currently PCM playback is supported. PCM capture will be supported in followed commits. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/dice/Makefile | 2 +- sound/firewire/dice/dice-pcm.c | 296 ++++++++++++++++++++++++++++++++++++++ sound/firewire/dice/dice-stream.c | 9 +- sound/firewire/dice/dice.c | 288 +------------------------------------ sound/firewire/dice/dice.h | 2 + 5 files changed, 305 insertions(+), 292 deletions(-) create mode 100644 sound/firewire/dice/dice-pcm.c (limited to 'sound') diff --git a/sound/firewire/dice/Makefile b/sound/firewire/dice/Makefile index 867864ca514f..1ddaeca9a137 100644 --- a/sound/firewire/dice/Makefile +++ b/sound/firewire/dice/Makefile @@ -1,2 +1,2 @@ -snd-dice-objs := dice-transaction.o dice-stream.o dice.o +snd-dice-objs := dice-transaction.o dice-stream.o dice-pcm.o dice.o obj-m += snd-dice.o diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c new file mode 100644 index 000000000000..deacb537eb81 --- /dev/null +++ b/sound/firewire/dice/dice-pcm.c @@ -0,0 +1,296 @@ +/* + * dice_pcm.c - a part of driver for DICE based devices + * + * Copyright (c) Clemens Ladisch + * Copyright (c) 2014 Takashi Sakamoto + * + * Licensed under the terms of the GNU General Public License, version 2. + */ + +#include "dice.h" + +static int dice_rate_constraint(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct snd_dice *dice = rule->private; + + const struct snd_interval *c = + hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_interval *r = + hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval rates = { + .min = UINT_MAX, .max = 0, .integer = 1 + }; + unsigned int i, rate, mode, *pcm_channels = dice->rx_channels; + + for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) { + rate = snd_dice_rates[i]; + if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0) + continue; + + if (!snd_interval_test(c, pcm_channels[mode])) + continue; + + rates.min = min(rates.min, rate); + rates.max = max(rates.max, rate); + } + + return snd_interval_refine(r, &rates); +} + +static int dice_channels_constraint(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct snd_dice *dice = rule->private; + + const struct snd_interval *r = + hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *c = + hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_interval channels = { + .min = UINT_MAX, .max = 0, .integer = 1 + }; + unsigned int i, rate, mode, *pcm_channels = dice->rx_channels; + + for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) { + rate = snd_dice_rates[i]; + if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0) + continue; + + if (!snd_interval_test(r, rate)) + continue; + + channels.min = min(channels.min, pcm_channels[mode]); + channels.max = max(channels.max, pcm_channels[mode]); + } + + return snd_interval_refine(c, &channels); +} + + +static int pcm_open(struct snd_pcm_substream *substream) +{ + static const struct snd_pcm_hardware hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_BATCH | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER, + .formats = AMDTP_OUT_PCM_FORMAT_BITS, + .channels_min = UINT_MAX, + .channels_max = 0, + .buffer_bytes_max = 16 * 1024 * 1024, + .period_bytes_min = 1, + .period_bytes_max = UINT_MAX, + .periods_min = 1, + .periods_max = UINT_MAX, + }; + struct snd_dice *dice = substream->private_data; + struct snd_pcm_runtime *runtime = substream->runtime; + unsigned int i; + int err; + + err = snd_dice_stream_lock_try(dice); + if (err < 0) + goto error; + + runtime->hw = hardware; + + for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) { + if (dice->clock_caps & (1 << i)) + runtime->hw.rates |= + snd_pcm_rate_to_rate_bit(snd_dice_rates[i]); + } + snd_pcm_limit_hw_rates(runtime); + + for (i = 0; i < 3; ++i) { + if (dice->rx_channels[i]) { + runtime->hw.channels_min = min(runtime->hw.channels_min, + dice->rx_channels[i]); + runtime->hw.channels_max = max(runtime->hw.channels_max, + dice->rx_channels[i]); + } + } + + err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + dice_rate_constraint, dice, + SNDRV_PCM_HW_PARAM_CHANNELS, -1); + if (err < 0) + goto err_lock; + err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + dice_channels_constraint, dice, + SNDRV_PCM_HW_PARAM_RATE, -1); + if (err < 0) + goto err_lock; + + err = amdtp_stream_add_pcm_hw_constraints(&dice->rx_stream, runtime); + if (err < 0) + goto err_lock; + + return 0; + +err_lock: + snd_dice_stream_lock_release(dice); +error: + return err; +} + +static int pcm_close(struct snd_pcm_substream *substream) +{ + struct snd_dice *dice = substream->private_data; + + snd_dice_stream_lock_release(dice); + + return 0; +} + +static int playback_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct snd_dice *dice = substream->private_data; + unsigned int mode, rate, channels, i; + int err; + + mutex_lock(&dice->mutex); + snd_dice_stream_stop(dice); + mutex_unlock(&dice->mutex); + + err = snd_pcm_lib_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); + if (err < 0) + return err; + + rate = params_rate(hw_params); + err = snd_dice_transaction_set_rate(dice, rate); + if (err < 0) + return err; + + if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0) + return err; + + /* + * At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in + * one data block of AMDTP packet. Thus sampling transfer frequency is + * a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are + * transferred on AMDTP packets at 96 kHz. Two successive samples of a + * channel are stored consecutively in the packet. This quirk is called + * as 'Dual Wire'. + * For this quirk, blocking mode is required and PCM buffer size should + * be aligned to SYT_INTERVAL. + */ + channels = params_channels(hw_params); + if (mode > 1) { + if (channels > AMDTP_MAX_CHANNELS_FOR_PCM / 2) { + err = -ENOSYS; + return err; + } + + rate /= 2; + channels *= 2; + dice->rx_stream.double_pcm_frames = true; + } else { + dice->rx_stream.double_pcm_frames = false; + } + + amdtp_stream_set_parameters(&dice->rx_stream, rate, channels, + dice->rx_midi_ports[mode]); + if (mode > 1) { + channels /= 2; + + for (i = 0; i < channels; i++) { + dice->rx_stream.pcm_positions[i] = i * 2; + dice->rx_stream.pcm_positions[i + channels] = i * 2 + 1; + } + } + + amdtp_stream_set_pcm_format(&dice->rx_stream, + params_format(hw_params)); + + return 0; +} + +static int playback_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_dice *dice = substream->private_data; + + mutex_lock(&dice->mutex); + snd_dice_stream_stop(dice); + mutex_unlock(&dice->mutex); + + return snd_pcm_lib_free_vmalloc_buffer(substream); +} + +static int playback_prepare(struct snd_pcm_substream *substream) +{ + struct snd_dice *dice = substream->private_data; + int err; + + mutex_lock(&dice->mutex); + + if (amdtp_streaming_error(&dice->rx_stream)) + snd_dice_stream_stop_packets(dice); + + err = snd_dice_stream_start(dice); + if (err < 0) { + mutex_unlock(&dice->mutex); + return err; + } + + mutex_unlock(&dice->mutex); + + amdtp_stream_pcm_prepare(&dice->rx_stream); + + return 0; +} + +static int playback_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_dice *dice = substream->private_data; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + amdtp_stream_pcm_trigger(&dice->rx_stream, substream); + break; + case SNDRV_PCM_TRIGGER_STOP: + amdtp_stream_pcm_trigger(&dice->rx_stream, NULL); + break; + default: + return -EINVAL; + } + + return 0; +} + +static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream) +{ + struct snd_dice *dice = substream->private_data; + + return amdtp_stream_pcm_pointer(&dice->rx_stream); +} + +int snd_dice_create_pcm(struct snd_dice *dice) +{ + static struct snd_pcm_ops playback_ops = { + .open = pcm_open, + .close = pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = playback_hw_params, + .hw_free = playback_hw_free, + .prepare = playback_prepare, + .trigger = playback_trigger, + .pointer = playback_pointer, + .page = snd_pcm_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, + }; + struct snd_pcm *pcm; + int err; + + err = snd_pcm_new(dice->card, "DICE", 0, 1, 0, &pcm); + if (err < 0) + return err; + pcm->private_data = dice; + strcpy(pcm->name, dice->card->shortname); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); + + return 0; +} diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index c25b9fb39d1f..4c4c4fff6272 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c @@ -96,10 +96,11 @@ error: void snd_dice_stream_stop_packets(struct snd_dice *dice) { - if (amdtp_stream_running(&dice->rx_stream)) { - snd_dice_transaction_clear_enable(dice); - amdtp_stream_stop(&dice->rx_stream); - } + if (!amdtp_stream_running(&dice->rx_stream)) + return; + + snd_dice_transaction_clear_enable(dice); + amdtp_stream_stop(&dice->rx_stream); } void snd_dice_stream_stop(struct snd_dice *dice) diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c index e032b1caa776..b76ed06e5c4d 100644 --- a/sound/firewire/dice/dice.c +++ b/sound/firewire/dice/dice.c @@ -11,292 +11,6 @@ MODULE_DESCRIPTION("DICE driver"); MODULE_AUTHOR("Clemens Ladisch "); MODULE_LICENSE("GPL v2"); -static int dice_rate_constraint(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - struct snd_dice *dice = rule->private; - - const struct snd_interval *c = - hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_interval *r = - hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval rates = { - .min = UINT_MAX, .max = 0, .integer = 1 - }; - unsigned int i, rate, mode, *pcm_channels = dice->rx_channels; - - for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) { - rate = snd_dice_rates[i]; - if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0) - continue; - - if (!snd_interval_test(c, pcm_channels[mode])) - continue; - - rates.min = min(rates.min, rate); - rates.max = max(rates.max, rate); - } - - return snd_interval_refine(r, &rates); -} - -static int dice_channels_constraint(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - struct snd_dice *dice = rule->private; - - const struct snd_interval *r = - hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *c = - hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_interval channels = { - .min = UINT_MAX, .max = 0, .integer = 1 - }; - unsigned int i, rate, mode, *pcm_channels = dice->rx_channels; - - for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) { - rate = snd_dice_rates[i]; - if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0) - continue; - - if (!snd_interval_test(r, rate)) - continue; - - channels.min = min(channels.min, pcm_channels[mode]); - channels.max = max(channels.max, pcm_channels[mode]); - } - - return snd_interval_refine(c, &channels); -} - -static int dice_open(struct snd_pcm_substream *substream) -{ - static const struct snd_pcm_hardware hardware = { - .info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_BATCH | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER, - .formats = AMDTP_OUT_PCM_FORMAT_BITS, - .channels_min = UINT_MAX, - .channels_max = 0, - .buffer_bytes_max = 16 * 1024 * 1024, - .period_bytes_min = 1, - .period_bytes_max = UINT_MAX, - .periods_min = 1, - .periods_max = UINT_MAX, - }; - struct snd_dice *dice = substream->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; - unsigned int i; - int err; - - err = snd_dice_stream_lock_try(dice); - if (err < 0) - goto error; - - runtime->hw = hardware; - - for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) - if (dice->clock_caps & (1 << i)) - runtime->hw.rates |= - snd_pcm_rate_to_rate_bit(snd_dice_rates[i]); - snd_pcm_limit_hw_rates(runtime); - - for (i = 0; i < 3; ++i) - if (dice->rx_channels[i]) { - runtime->hw.channels_min = min(runtime->hw.channels_min, - dice->rx_channels[i]); - runtime->hw.channels_max = max(runtime->hw.channels_max, - dice->rx_channels[i]); - } - - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - dice_rate_constraint, dice, - SNDRV_PCM_HW_PARAM_CHANNELS, -1); - if (err < 0) - goto err_lock; - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - dice_channels_constraint, dice, - SNDRV_PCM_HW_PARAM_RATE, -1); - if (err < 0) - goto err_lock; - - err = amdtp_stream_add_pcm_hw_constraints(&dice->rx_stream, runtime); - if (err < 0) - goto err_lock; - - return 0; - -err_lock: - snd_dice_stream_lock_release(dice); -error: - return err; -} - -static int dice_close(struct snd_pcm_substream *substream) -{ - struct snd_dice *dice = substream->private_data; - - snd_dice_stream_lock_release(dice); - - return 0; -} - -static int dice_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct snd_dice *dice = substream->private_data; - unsigned int mode, rate, channels, i; - int err; - - mutex_lock(&dice->mutex); - snd_dice_stream_stop(dice); - mutex_unlock(&dice->mutex); - - err = snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); - if (err < 0) - return err; - - rate = params_rate(hw_params); - err = snd_dice_transaction_set_rate(dice, rate); - if (err < 0) - return err; - - err = snd_dice_stream_get_rate_mode(dice, rate, &mode); - if (err < 0) - return err; - - /* - * At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in - * one data block of AMDTP packet. Thus sampling transfer frequency is - * a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are - * transferred on AMDTP packets at 96 kHz. Two successive samples of a - * channel are stored consecutively in the packet. This quirk is called - * as 'Dual Wire'. - * For this quirk, blocking mode is required and PCM buffer size should - * be aligned to SYT_INTERVAL. - */ - channels = params_channels(hw_params); - if (mode > 1) { - if (channels > AMDTP_MAX_CHANNELS_FOR_PCM / 2) { - err = -ENOSYS; - return err; - } - - rate /= 2; - channels *= 2; - dice->rx_stream.double_pcm_frames = true; - } else { - dice->rx_stream.double_pcm_frames = false; - } - - amdtp_stream_set_parameters(&dice->rx_stream, rate, channels, - dice->rx_midi_ports[mode]); - if (mode > 4) { - channels /= 2; - - for (i = 0; i < channels; i++) { - dice->rx_stream.pcm_positions[i] = i * 2; - dice->rx_stream.pcm_positions[i + channels] = i * 2 + 1; - } - } - - amdtp_stream_set_pcm_format(&dice->rx_stream, - params_format(hw_params)); - - return 0; -} - -static int dice_hw_free(struct snd_pcm_substream *substream) -{ - struct snd_dice *dice = substream->private_data; - - mutex_lock(&dice->mutex); - snd_dice_stream_stop(dice); - mutex_unlock(&dice->mutex); - - return snd_pcm_lib_free_vmalloc_buffer(substream); -} - -static int dice_prepare(struct snd_pcm_substream *substream) -{ - struct snd_dice *dice = substream->private_data; - int err; - - mutex_lock(&dice->mutex); - - if (amdtp_streaming_error(&dice->rx_stream)) - snd_dice_stream_stop_packets(dice); - - err = snd_dice_stream_start(dice); - if (err < 0) { - mutex_unlock(&dice->mutex); - return err; - } - - mutex_unlock(&dice->mutex); - - amdtp_stream_pcm_prepare(&dice->rx_stream); - - return 0; -} - -static int dice_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct snd_dice *dice = substream->private_data; - struct snd_pcm_substream *pcm; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - pcm = substream; - break; - case SNDRV_PCM_TRIGGER_STOP: - pcm = NULL; - break; - default: - return -EINVAL; - } - amdtp_stream_pcm_trigger(&dice->rx_stream, pcm); - - return 0; -} - -static snd_pcm_uframes_t dice_pointer(struct snd_pcm_substream *substream) -{ - struct snd_dice *dice = substream->private_data; - - return amdtp_stream_pcm_pointer(&dice->rx_stream); -} - -static int dice_create_pcm(struct snd_dice *dice) -{ - static struct snd_pcm_ops ops = { - .open = dice_open, - .close = dice_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = dice_hw_params, - .hw_free = dice_hw_free, - .prepare = dice_prepare, - .trigger = dice_trigger, - .pointer = dice_pointer, - .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, - }; - struct snd_pcm *pcm; - int err; - - err = snd_pcm_new(dice->card, "DICE", 0, 1, 0, &pcm); - if (err < 0) - return err; - pcm->private_data = dice; - strcpy(pcm->name, dice->card->shortname); - pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->ops = &ops; - - return 0; -} - static long dice_hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count, loff_t *offset) { @@ -978,7 +692,7 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) dice_card_strings(dice); - err = dice_create_pcm(dice); + err = snd_dice_create_pcm(dice); if (err < 0) goto error; diff --git a/sound/firewire/dice/dice.h b/sound/firewire/dice/dice.h index ca4090d881e6..4d9e55ba895b 100644 --- a/sound/firewire/dice/dice.h +++ b/sound/firewire/dice/dice.h @@ -171,4 +171,6 @@ void snd_dice_stream_update(struct snd_dice *dice); int snd_dice_stream_lock_try(struct snd_dice *dice); void snd_dice_stream_lock_release(struct snd_dice *dice); +int snd_dice_create_pcm(struct snd_dice *dice); + #endif -- cgit v1.2.3 From 19af57b46dda93b34902739673d5f37d8c6d0d5f Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sat, 29 Nov 2014 00:59:16 +0900 Subject: ALSA: dice: Split hwdep functionality into a file This commit adds a file and move some codes related to hwdep functionality. This interface is designed for mixer/control application. By using hwdep interface, the application can get information about firewire node, can lock/unlock kernel streaming and can get notification at starting/stopping kernel streaming. Additionally, this interface give a way to read Dice notification. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/dice/Makefile | 3 +- sound/firewire/dice/dice-hwdep.c | 190 +++++++++++++++++++++++++++++++++++++++ sound/firewire/dice/dice.c | 182 +------------------------------------ sound/firewire/dice/dice.h | 2 + 4 files changed, 195 insertions(+), 182 deletions(-) create mode 100644 sound/firewire/dice/dice-hwdep.c (limited to 'sound') diff --git a/sound/firewire/dice/Makefile b/sound/firewire/dice/Makefile index 1ddaeca9a137..73b0e38803cb 100644 --- a/sound/firewire/dice/Makefile +++ b/sound/firewire/dice/Makefile @@ -1,2 +1,3 @@ -snd-dice-objs := dice-transaction.o dice-stream.o dice-pcm.o dice.o +snd-dice-objs := dice-transaction.o dice-stream.o dice-pcm.o dice-hwdep.o \ + dice.o obj-m += snd-dice.o diff --git a/sound/firewire/dice/dice-hwdep.c b/sound/firewire/dice/dice-hwdep.c new file mode 100644 index 000000000000..a4dc02a86f12 --- /dev/null +++ b/sound/firewire/dice/dice-hwdep.c @@ -0,0 +1,190 @@ +/* + * dice_hwdep.c - a part of driver for DICE based devices + * + * Copyright (c) Clemens Ladisch + * Copyright (c) 2014 Takashi Sakamoto + * + * Licensed under the terms of the GNU General Public License, version 2. + */ + +#include "dice.h" + +static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, + long count, loff_t *offset) +{ + struct snd_dice *dice = hwdep->private_data; + DEFINE_WAIT(wait); + union snd_firewire_event event; + + spin_lock_irq(&dice->lock); + + while (!dice->dev_lock_changed && dice->notification_bits == 0) { + prepare_to_wait(&dice->hwdep_wait, &wait, TASK_INTERRUPTIBLE); + spin_unlock_irq(&dice->lock); + schedule(); + finish_wait(&dice->hwdep_wait, &wait); + if (signal_pending(current)) + return -ERESTARTSYS; + spin_lock_irq(&dice->lock); + } + + memset(&event, 0, sizeof(event)); + if (dice->dev_lock_changed) { + event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS; + event.lock_status.status = dice->dev_lock_count > 0; + dice->dev_lock_changed = false; + + count = min_t(long, count, sizeof(event.lock_status)); + } else { + event.dice_notification.type = + SNDRV_FIREWIRE_EVENT_DICE_NOTIFICATION; + event.dice_notification.notification = dice->notification_bits; + dice->notification_bits = 0; + + count = min_t(long, count, sizeof(event.dice_notification)); + } + + spin_unlock_irq(&dice->lock); + + if (copy_to_user(buf, &event, count)) + return -EFAULT; + + return count; +} + +static unsigned int hwdep_poll(struct snd_hwdep *hwdep, struct file *file, + poll_table *wait) +{ + struct snd_dice *dice = hwdep->private_data; + unsigned int events; + + poll_wait(file, &dice->hwdep_wait, wait); + + spin_lock_irq(&dice->lock); + if (dice->dev_lock_changed || dice->notification_bits != 0) + events = POLLIN | POLLRDNORM; + else + events = 0; + spin_unlock_irq(&dice->lock); + + return events; +} + +static int hwdep_get_info(struct snd_dice *dice, void __user *arg) +{ + struct fw_device *dev = fw_parent_device(dice->unit); + struct snd_firewire_get_info info; + + memset(&info, 0, sizeof(info)); + info.type = SNDRV_FIREWIRE_TYPE_DICE; + info.card = dev->card->index; + *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]); + *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]); + strlcpy(info.device_name, dev_name(&dev->device), + sizeof(info.device_name)); + + if (copy_to_user(arg, &info, sizeof(info))) + return -EFAULT; + + return 0; +} + +static int hwdep_lock(struct snd_dice *dice) +{ + int err; + + spin_lock_irq(&dice->lock); + + if (dice->dev_lock_count == 0) { + dice->dev_lock_count = -1; + err = 0; + } else { + err = -EBUSY; + } + + spin_unlock_irq(&dice->lock); + + return err; +} + +static int hwdep_unlock(struct snd_dice *dice) +{ + int err; + + spin_lock_irq(&dice->lock); + + if (dice->dev_lock_count == -1) { + dice->dev_lock_count = 0; + err = 0; + } else { + err = -EBADFD; + } + + spin_unlock_irq(&dice->lock); + + return err; +} + +static int hwdep_release(struct snd_hwdep *hwdep, struct file *file) +{ + struct snd_dice *dice = hwdep->private_data; + + spin_lock_irq(&dice->lock); + if (dice->dev_lock_count == -1) + dice->dev_lock_count = 0; + spin_unlock_irq(&dice->lock); + + return 0; +} + +static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct snd_dice *dice = hwdep->private_data; + + switch (cmd) { + case SNDRV_FIREWIRE_IOCTL_GET_INFO: + return hwdep_get_info(dice, (void __user *)arg); + case SNDRV_FIREWIRE_IOCTL_LOCK: + return hwdep_lock(dice); + case SNDRV_FIREWIRE_IOCTL_UNLOCK: + return hwdep_unlock(dice); + default: + return -ENOIOCTLCMD; + } +} + +#ifdef CONFIG_COMPAT +static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file, + unsigned int cmd, unsigned long arg) +{ + return hwdep_ioctl(hwdep, file, cmd, + (unsigned long)compat_ptr(arg)); +} +#else +#define hwdep_compat_ioctl NULL +#endif + +int snd_dice_create_hwdep(struct snd_dice *dice) +{ + static const struct snd_hwdep_ops ops = { + .read = hwdep_read, + .release = hwdep_release, + .poll = hwdep_poll, + .ioctl = hwdep_ioctl, + .ioctl_compat = hwdep_compat_ioctl, + }; + struct snd_hwdep *hwdep; + int err; + + err = snd_hwdep_new(dice->card, "DICE", 0, &hwdep); + if (err < 0) + return err; + strcpy(hwdep->name, "DICE"); + hwdep->iface = SNDRV_HWDEP_IFACE_FW_DICE; + hwdep->ops = ops; + hwdep->private_data = dice; + hwdep->exclusive = true; + + return 0; +} diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c index b76ed06e5c4d..dbc1239c95ee 100644 --- a/sound/firewire/dice/dice.c +++ b/sound/firewire/dice/dice.c @@ -11,186 +11,6 @@ MODULE_DESCRIPTION("DICE driver"); MODULE_AUTHOR("Clemens Ladisch "); MODULE_LICENSE("GPL v2"); -static long dice_hwdep_read(struct snd_hwdep *hwdep, char __user *buf, - long count, loff_t *offset) -{ - struct snd_dice *dice = hwdep->private_data; - DEFINE_WAIT(wait); - union snd_firewire_event event; - - spin_lock_irq(&dice->lock); - - while (!dice->dev_lock_changed && dice->notification_bits == 0) { - prepare_to_wait(&dice->hwdep_wait, &wait, TASK_INTERRUPTIBLE); - spin_unlock_irq(&dice->lock); - schedule(); - finish_wait(&dice->hwdep_wait, &wait); - if (signal_pending(current)) - return -ERESTARTSYS; - spin_lock_irq(&dice->lock); - } - - memset(&event, 0, sizeof(event)); - if (dice->dev_lock_changed) { - event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS; - event.lock_status.status = dice->dev_lock_count > 0; - dice->dev_lock_changed = false; - - count = min_t(long, count, sizeof(event.lock_status)); - } else { - event.dice_notification.type = - SNDRV_FIREWIRE_EVENT_DICE_NOTIFICATION; - event.dice_notification.notification = dice->notification_bits; - dice->notification_bits = 0; - - count = min_t(long, count, sizeof(event.dice_notification)); - } - - spin_unlock_irq(&dice->lock); - - if (copy_to_user(buf, &event, count)) - return -EFAULT; - - return count; -} - -static unsigned int dice_hwdep_poll(struct snd_hwdep *hwdep, struct file *file, - poll_table *wait) -{ - struct snd_dice *dice = hwdep->private_data; - unsigned int events; - - poll_wait(file, &dice->hwdep_wait, wait); - - spin_lock_irq(&dice->lock); - if (dice->dev_lock_changed || dice->notification_bits != 0) - events = POLLIN | POLLRDNORM; - else - events = 0; - spin_unlock_irq(&dice->lock); - - return events; -} - -static int dice_hwdep_get_info(struct snd_dice *dice, void __user *arg) -{ - struct fw_device *dev = fw_parent_device(dice->unit); - struct snd_firewire_get_info info; - - memset(&info, 0, sizeof(info)); - info.type = SNDRV_FIREWIRE_TYPE_DICE; - info.card = dev->card->index; - *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]); - *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]); - strlcpy(info.device_name, dev_name(&dev->device), - sizeof(info.device_name)); - - if (copy_to_user(arg, &info, sizeof(info))) - return -EFAULT; - - return 0; -} - -static int dice_hwdep_lock(struct snd_dice *dice) -{ - int err; - - spin_lock_irq(&dice->lock); - - if (dice->dev_lock_count == 0) { - dice->dev_lock_count = -1; - err = 0; - } else { - err = -EBUSY; - } - - spin_unlock_irq(&dice->lock); - - return err; -} - -static int dice_hwdep_unlock(struct snd_dice *dice) -{ - int err; - - spin_lock_irq(&dice->lock); - - if (dice->dev_lock_count == -1) { - dice->dev_lock_count = 0; - err = 0; - } else { - err = -EBADFD; - } - - spin_unlock_irq(&dice->lock); - - return err; -} - -static int dice_hwdep_release(struct snd_hwdep *hwdep, struct file *file) -{ - struct snd_dice *dice = hwdep->private_data; - - spin_lock_irq(&dice->lock); - if (dice->dev_lock_count == -1) - dice->dev_lock_count = 0; - spin_unlock_irq(&dice->lock); - - return 0; -} - -static int dice_hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct snd_dice *dice = hwdep->private_data; - - switch (cmd) { - case SNDRV_FIREWIRE_IOCTL_GET_INFO: - return dice_hwdep_get_info(dice, (void __user *)arg); - case SNDRV_FIREWIRE_IOCTL_LOCK: - return dice_hwdep_lock(dice); - case SNDRV_FIREWIRE_IOCTL_UNLOCK: - return dice_hwdep_unlock(dice); - default: - return -ENOIOCTLCMD; - } -} - -#ifdef CONFIG_COMPAT -static int dice_hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file, - unsigned int cmd, unsigned long arg) -{ - return dice_hwdep_ioctl(hwdep, file, cmd, - (unsigned long)compat_ptr(arg)); -} -#else -#define dice_hwdep_compat_ioctl NULL -#endif - -static int dice_create_hwdep(struct snd_dice *dice) -{ - static const struct snd_hwdep_ops ops = { - .read = dice_hwdep_read, - .release = dice_hwdep_release, - .poll = dice_hwdep_poll, - .ioctl = dice_hwdep_ioctl, - .ioctl_compat = dice_hwdep_compat_ioctl, - }; - struct snd_hwdep *hwdep; - int err; - - err = snd_hwdep_new(dice->card, "DICE", 0, &hwdep); - if (err < 0) - return err; - strcpy(hwdep->name, "DICE"); - hwdep->iface = SNDRV_HWDEP_IFACE_FW_DICE; - hwdep->ops = ops; - hwdep->private_data = dice; - hwdep->exclusive = true; - - return 0; -} - static int dice_proc_read_mem(struct snd_dice *dice, void *buffer, unsigned int offset_q, unsigned int quadlets) { @@ -696,7 +516,7 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) if (err < 0) goto error; - err = dice_create_hwdep(dice); + err = snd_dice_create_hwdep(dice); if (err < 0) goto error; diff --git a/sound/firewire/dice/dice.h b/sound/firewire/dice/dice.h index 4d9e55ba895b..dcc8c789cd43 100644 --- a/sound/firewire/dice/dice.h +++ b/sound/firewire/dice/dice.h @@ -173,4 +173,6 @@ void snd_dice_stream_lock_release(struct snd_dice *dice); int snd_dice_create_pcm(struct snd_dice *dice); +int snd_dice_create_hwdep(struct snd_dice *dice); + #endif -- cgit v1.2.3 From 04d426a039691bf114997a8af877682fdffcebd7 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sat, 29 Nov 2014 00:59:17 +0900 Subject: ALSA: dice: Split proc interface into a file This commit adds a file and move some codes related to proc output. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/dice/Makefile | 4 +- sound/firewire/dice/dice-proc.c | 252 ++++++++++++++++++++++++++++++++++++++++ sound/firewire/dice/dice.c | 244 +------------------------------------- sound/firewire/dice/dice.h | 2 + 4 files changed, 257 insertions(+), 245 deletions(-) create mode 100644 sound/firewire/dice/dice-proc.c (limited to 'sound') diff --git a/sound/firewire/dice/Makefile b/sound/firewire/dice/Makefile index 73b0e38803cb..9a48289eb9cb 100644 --- a/sound/firewire/dice/Makefile +++ b/sound/firewire/dice/Makefile @@ -1,3 +1,3 @@ -snd-dice-objs := dice-transaction.o dice-stream.o dice-pcm.o dice-hwdep.o \ - dice.o +snd-dice-objs := dice-transaction.o dice-stream.o dice-proc.o dice-pcm.o \ + dice-hwdep.o dice.o obj-m += snd-dice.o diff --git a/sound/firewire/dice/dice-proc.c b/sound/firewire/dice/dice-proc.c new file mode 100644 index 000000000000..f5c1d1bced59 --- /dev/null +++ b/sound/firewire/dice/dice-proc.c @@ -0,0 +1,252 @@ +/* + * dice_proc.c - a part of driver for Dice based devices + * + * Copyright (c) Clemens Ladisch + * Copyright (c) 2014 Takashi Sakamoto + * + * Licensed under the terms of the GNU General Public License, version 2. + */ + +#include "dice.h" + +static int dice_proc_read_mem(struct snd_dice *dice, void *buffer, + unsigned int offset_q, unsigned int quadlets) +{ + unsigned int i; + int err; + + err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST, + DICE_PRIVATE_SPACE + 4 * offset_q, + buffer, 4 * quadlets, 0); + if (err < 0) + return err; + + for (i = 0; i < quadlets; ++i) + be32_to_cpus(&((u32 *)buffer)[i]); + + return 0; +} + +static const char *str_from_array(const char *const strs[], unsigned int count, + unsigned int i) +{ + if (i < count) + return strs[i]; + + return "(unknown)"; +} + +static void dice_proc_fixup_string(char *s, unsigned int size) +{ + unsigned int i; + + for (i = 0; i < size; i += 4) + cpu_to_le32s((u32 *)(s + i)); + + for (i = 0; i < size - 2; ++i) { + if (s[i] == '\0') + return; + if (s[i] == '\\' && s[i + 1] == '\\') { + s[i + 2] = '\0'; + return; + } + } + s[size - 1] = '\0'; +} + +static void dice_proc_read(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + static const char *const section_names[5] = { + "global", "tx", "rx", "ext_sync", "unused2" + }; + static const char *const clock_sources[] = { + "aes1", "aes2", "aes3", "aes4", "aes", "adat", "tdif", + "wc", "arx1", "arx2", "arx3", "arx4", "internal" + }; + static const char *const rates[] = { + "32000", "44100", "48000", "88200", "96000", "176400", "192000", + "any low", "any mid", "any high", "none" + }; + struct snd_dice *dice = entry->private_data; + u32 sections[ARRAY_SIZE(section_names) * 2]; + struct { + u32 number; + u32 size; + } tx_rx_header; + union { + struct { + u32 owner_hi, owner_lo; + u32 notification; + char nick_name[NICK_NAME_SIZE]; + u32 clock_select; + u32 enable; + u32 status; + u32 extended_status; + u32 sample_rate; + u32 version; + u32 clock_caps; + char clock_source_names[CLOCK_SOURCE_NAMES_SIZE]; + } global; + struct { + u32 iso; + u32 number_audio; + u32 number_midi; + u32 speed; + char names[TX_NAMES_SIZE]; + u32 ac3_caps; + u32 ac3_enable; + } tx; + struct { + u32 iso; + u32 seq_start; + u32 number_audio; + u32 number_midi; + char names[RX_NAMES_SIZE]; + u32 ac3_caps; + u32 ac3_enable; + } rx; + struct { + u32 clock_source; + u32 locked; + u32 rate; + u32 adat_user_data; + } ext_sync; + } buf; + unsigned int quadlets, stream, i; + + if (dice_proc_read_mem(dice, sections, 0, ARRAY_SIZE(sections)) < 0) + return; + snd_iprintf(buffer, "sections:\n"); + for (i = 0; i < ARRAY_SIZE(section_names); ++i) + snd_iprintf(buffer, " %s: offset %u, size %u\n", + section_names[i], + sections[i * 2], sections[i * 2 + 1]); + + quadlets = min_t(u32, sections[1], sizeof(buf.global) / 4); + if (dice_proc_read_mem(dice, &buf.global, sections[0], quadlets) < 0) + return; + snd_iprintf(buffer, "global:\n"); + snd_iprintf(buffer, " owner: %04x:%04x%08x\n", + buf.global.owner_hi >> 16, + buf.global.owner_hi & 0xffff, buf.global.owner_lo); + snd_iprintf(buffer, " notification: %08x\n", buf.global.notification); + dice_proc_fixup_string(buf.global.nick_name, NICK_NAME_SIZE); + snd_iprintf(buffer, " nick name: %s\n", buf.global.nick_name); + snd_iprintf(buffer, " clock select: %s %s\n", + str_from_array(clock_sources, ARRAY_SIZE(clock_sources), + buf.global.clock_select & CLOCK_SOURCE_MASK), + str_from_array(rates, ARRAY_SIZE(rates), + (buf.global.clock_select & CLOCK_RATE_MASK) + >> CLOCK_RATE_SHIFT)); + snd_iprintf(buffer, " enable: %u\n", buf.global.enable); + snd_iprintf(buffer, " status: %slocked %s\n", + buf.global.status & STATUS_SOURCE_LOCKED ? "" : "un", + str_from_array(rates, ARRAY_SIZE(rates), + (buf.global.status & + STATUS_NOMINAL_RATE_MASK) + >> CLOCK_RATE_SHIFT)); + snd_iprintf(buffer, " ext status: %08x\n", buf.global.extended_status); + snd_iprintf(buffer, " sample rate: %u\n", buf.global.sample_rate); + snd_iprintf(buffer, " version: %u.%u.%u.%u\n", + (buf.global.version >> 24) & 0xff, + (buf.global.version >> 16) & 0xff, + (buf.global.version >> 8) & 0xff, + (buf.global.version >> 0) & 0xff); + if (quadlets >= 90) { + snd_iprintf(buffer, " clock caps:"); + for (i = 0; i <= 6; ++i) + if (buf.global.clock_caps & (1 << i)) + snd_iprintf(buffer, " %s", rates[i]); + for (i = 0; i <= 12; ++i) + if (buf.global.clock_caps & (1 << (16 + i))) + snd_iprintf(buffer, " %s", clock_sources[i]); + snd_iprintf(buffer, "\n"); + dice_proc_fixup_string(buf.global.clock_source_names, + CLOCK_SOURCE_NAMES_SIZE); + snd_iprintf(buffer, " clock source names: %s\n", + buf.global.clock_source_names); + } + + if (dice_proc_read_mem(dice, &tx_rx_header, sections[2], 2) < 0) + return; + quadlets = min_t(u32, tx_rx_header.size, sizeof(buf.tx) / 4); + for (stream = 0; stream < tx_rx_header.number; ++stream) { + if (dice_proc_read_mem(dice, &buf.tx, sections[2] + 2 + + stream * tx_rx_header.size, + quadlets) < 0) + break; + snd_iprintf(buffer, "tx %u:\n", stream); + snd_iprintf(buffer, " iso channel: %d\n", (int)buf.tx.iso); + snd_iprintf(buffer, " audio channels: %u\n", + buf.tx.number_audio); + snd_iprintf(buffer, " midi ports: %u\n", buf.tx.number_midi); + snd_iprintf(buffer, " speed: S%u\n", 100u << buf.tx.speed); + if (quadlets >= 68) { + dice_proc_fixup_string(buf.tx.names, TX_NAMES_SIZE); + snd_iprintf(buffer, " names: %s\n", buf.tx.names); + } + if (quadlets >= 70) { + snd_iprintf(buffer, " ac3 caps: %08x\n", + buf.tx.ac3_caps); + snd_iprintf(buffer, " ac3 enable: %08x\n", + buf.tx.ac3_enable); + } + } + + if (dice_proc_read_mem(dice, &tx_rx_header, sections[4], 2) < 0) + return; + quadlets = min_t(u32, tx_rx_header.size, sizeof(buf.rx) / 4); + for (stream = 0; stream < tx_rx_header.number; ++stream) { + if (dice_proc_read_mem(dice, &buf.rx, sections[4] + 2 + + stream * tx_rx_header.size, + quadlets) < 0) + break; + snd_iprintf(buffer, "rx %u:\n", stream); + snd_iprintf(buffer, " iso channel: %d\n", (int)buf.rx.iso); + snd_iprintf(buffer, " sequence start: %u\n", buf.rx.seq_start); + snd_iprintf(buffer, " audio channels: %u\n", + buf.rx.number_audio); + snd_iprintf(buffer, " midi ports: %u\n", buf.rx.number_midi); + if (quadlets >= 68) { + dice_proc_fixup_string(buf.rx.names, RX_NAMES_SIZE); + snd_iprintf(buffer, " names: %s\n", buf.rx.names); + } + if (quadlets >= 70) { + snd_iprintf(buffer, " ac3 caps: %08x\n", + buf.rx.ac3_caps); + snd_iprintf(buffer, " ac3 enable: %08x\n", + buf.rx.ac3_enable); + } + } + + quadlets = min_t(u32, sections[7], sizeof(buf.ext_sync) / 4); + if (quadlets >= 4) { + if (dice_proc_read_mem(dice, &buf.ext_sync, + sections[6], 4) < 0) + return; + snd_iprintf(buffer, "ext status:\n"); + snd_iprintf(buffer, " clock source: %s\n", + str_from_array(clock_sources, + ARRAY_SIZE(clock_sources), + buf.ext_sync.clock_source)); + snd_iprintf(buffer, " locked: %u\n", buf.ext_sync.locked); + snd_iprintf(buffer, " rate: %s\n", + str_from_array(rates, ARRAY_SIZE(rates), + buf.ext_sync.rate)); + snd_iprintf(buffer, " adat user data: "); + if (buf.ext_sync.adat_user_data & ADAT_USER_DATA_NO_DATA) + snd_iprintf(buffer, "-\n"); + else + snd_iprintf(buffer, "%x\n", + buf.ext_sync.adat_user_data); + } +} + +void snd_dice_create_proc(struct snd_dice *dice) +{ + struct snd_info_entry *entry; + + if (!snd_card_proc_new(dice->card, "dice", &entry)) + snd_info_set_text_ops(entry, dice, dice_proc_read); +} diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c index dbc1239c95ee..8e2c172de8a7 100644 --- a/sound/firewire/dice/dice.c +++ b/sound/firewire/dice/dice.c @@ -11,248 +11,6 @@ MODULE_DESCRIPTION("DICE driver"); MODULE_AUTHOR("Clemens Ladisch "); MODULE_LICENSE("GPL v2"); -static int dice_proc_read_mem(struct snd_dice *dice, void *buffer, - unsigned int offset_q, unsigned int quadlets) -{ - unsigned int i; - int err; - - err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST, - DICE_PRIVATE_SPACE + 4 * offset_q, - buffer, 4 * quadlets, 0); - if (err < 0) - return err; - - for (i = 0; i < quadlets; ++i) - be32_to_cpus(&((u32 *)buffer)[i]); - - return 0; -} - -static const char *str_from_array(const char *const strs[], unsigned int count, - unsigned int i) -{ - if (i < count) - return strs[i]; - - return "(unknown)"; -} - -static void dice_proc_fixup_string(char *s, unsigned int size) -{ - unsigned int i; - - for (i = 0; i < size; i += 4) - cpu_to_le32s((u32 *)(s + i)); - - for (i = 0; i < size - 2; ++i) { - if (s[i] == '\0') - return; - if (s[i] == '\\' && s[i + 1] == '\\') { - s[i + 2] = '\0'; - return; - } - } - s[size - 1] = '\0'; -} - -static void dice_proc_read(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) -{ - static const char *const section_names[5] = { - "global", "tx", "rx", "ext_sync", "unused2" - }; - static const char *const clock_sources[] = { - "aes1", "aes2", "aes3", "aes4", "aes", "adat", "tdif", - "wc", "arx1", "arx2", "arx3", "arx4", "internal" - }; - static const char *const rates[] = { - "32000", "44100", "48000", "88200", "96000", "176400", "192000", - "any low", "any mid", "any high", "none" - }; - struct snd_dice *dice = entry->private_data; - u32 sections[ARRAY_SIZE(section_names) * 2]; - struct { - u32 number; - u32 size; - } tx_rx_header; - union { - struct { - u32 owner_hi, owner_lo; - u32 notification; - char nick_name[NICK_NAME_SIZE]; - u32 clock_select; - u32 enable; - u32 status; - u32 extended_status; - u32 sample_rate; - u32 version; - u32 clock_caps; - char clock_source_names[CLOCK_SOURCE_NAMES_SIZE]; - } global; - struct { - u32 iso; - u32 number_audio; - u32 number_midi; - u32 speed; - char names[TX_NAMES_SIZE]; - u32 ac3_caps; - u32 ac3_enable; - } tx; - struct { - u32 iso; - u32 seq_start; - u32 number_audio; - u32 number_midi; - char names[RX_NAMES_SIZE]; - u32 ac3_caps; - u32 ac3_enable; - } rx; - struct { - u32 clock_source; - u32 locked; - u32 rate; - u32 adat_user_data; - } ext_sync; - } buf; - unsigned int quadlets, stream, i; - - if (dice_proc_read_mem(dice, sections, 0, ARRAY_SIZE(sections)) < 0) - return; - snd_iprintf(buffer, "sections:\n"); - for (i = 0; i < ARRAY_SIZE(section_names); ++i) - snd_iprintf(buffer, " %s: offset %u, size %u\n", - section_names[i], - sections[i * 2], sections[i * 2 + 1]); - - quadlets = min_t(u32, sections[1], sizeof(buf.global) / 4); - if (dice_proc_read_mem(dice, &buf.global, sections[0], quadlets) < 0) - return; - snd_iprintf(buffer, "global:\n"); - snd_iprintf(buffer, " owner: %04x:%04x%08x\n", - buf.global.owner_hi >> 16, - buf.global.owner_hi & 0xffff, buf.global.owner_lo); - snd_iprintf(buffer, " notification: %08x\n", buf.global.notification); - dice_proc_fixup_string(buf.global.nick_name, NICK_NAME_SIZE); - snd_iprintf(buffer, " nick name: %s\n", buf.global.nick_name); - snd_iprintf(buffer, " clock select: %s %s\n", - str_from_array(clock_sources, ARRAY_SIZE(clock_sources), - buf.global.clock_select & CLOCK_SOURCE_MASK), - str_from_array(rates, ARRAY_SIZE(rates), - (buf.global.clock_select & CLOCK_RATE_MASK) - >> CLOCK_RATE_SHIFT)); - snd_iprintf(buffer, " enable: %u\n", buf.global.enable); - snd_iprintf(buffer, " status: %slocked %s\n", - buf.global.status & STATUS_SOURCE_LOCKED ? "" : "un", - str_from_array(rates, ARRAY_SIZE(rates), - (buf.global.status & - STATUS_NOMINAL_RATE_MASK) - >> CLOCK_RATE_SHIFT)); - snd_iprintf(buffer, " ext status: %08x\n", buf.global.extended_status); - snd_iprintf(buffer, " sample rate: %u\n", buf.global.sample_rate); - snd_iprintf(buffer, " version: %u.%u.%u.%u\n", - (buf.global.version >> 24) & 0xff, - (buf.global.version >> 16) & 0xff, - (buf.global.version >> 8) & 0xff, - (buf.global.version >> 0) & 0xff); - if (quadlets >= 90) { - snd_iprintf(buffer, " clock caps:"); - for (i = 0; i <= 6; ++i) - if (buf.global.clock_caps & (1 << i)) - snd_iprintf(buffer, " %s", rates[i]); - for (i = 0; i <= 12; ++i) - if (buf.global.clock_caps & (1 << (16 + i))) - snd_iprintf(buffer, " %s", clock_sources[i]); - snd_iprintf(buffer, "\n"); - dice_proc_fixup_string(buf.global.clock_source_names, - CLOCK_SOURCE_NAMES_SIZE); - snd_iprintf(buffer, " clock source names: %s\n", - buf.global.clock_source_names); - } - - if (dice_proc_read_mem(dice, &tx_rx_header, sections[2], 2) < 0) - return; - quadlets = min_t(u32, tx_rx_header.size, sizeof(buf.tx) / 4); - for (stream = 0; stream < tx_rx_header.number; ++stream) { - if (dice_proc_read_mem(dice, &buf.tx, sections[2] + 2 + - stream * tx_rx_header.size, - quadlets) < 0) - break; - snd_iprintf(buffer, "tx %u:\n", stream); - snd_iprintf(buffer, " iso channel: %d\n", (int)buf.tx.iso); - snd_iprintf(buffer, " audio channels: %u\n", - buf.tx.number_audio); - snd_iprintf(buffer, " midi ports: %u\n", buf.tx.number_midi); - snd_iprintf(buffer, " speed: S%u\n", 100u << buf.tx.speed); - if (quadlets >= 68) { - dice_proc_fixup_string(buf.tx.names, TX_NAMES_SIZE); - snd_iprintf(buffer, " names: %s\n", buf.tx.names); - } - if (quadlets >= 70) { - snd_iprintf(buffer, " ac3 caps: %08x\n", - buf.tx.ac3_caps); - snd_iprintf(buffer, " ac3 enable: %08x\n", - buf.tx.ac3_enable); - } - } - - if (dice_proc_read_mem(dice, &tx_rx_header, sections[4], 2) < 0) - return; - quadlets = min_t(u32, tx_rx_header.size, sizeof(buf.rx) / 4); - for (stream = 0; stream < tx_rx_header.number; ++stream) { - if (dice_proc_read_mem(dice, &buf.rx, sections[4] + 2 + - stream * tx_rx_header.size, - quadlets) < 0) - break; - snd_iprintf(buffer, "rx %u:\n", stream); - snd_iprintf(buffer, " iso channel: %d\n", (int)buf.rx.iso); - snd_iprintf(buffer, " sequence start: %u\n", buf.rx.seq_start); - snd_iprintf(buffer, " audio channels: %u\n", - buf.rx.number_audio); - snd_iprintf(buffer, " midi ports: %u\n", buf.rx.number_midi); - if (quadlets >= 68) { - dice_proc_fixup_string(buf.rx.names, RX_NAMES_SIZE); - snd_iprintf(buffer, " names: %s\n", buf.rx.names); - } - if (quadlets >= 70) { - snd_iprintf(buffer, " ac3 caps: %08x\n", - buf.rx.ac3_caps); - snd_iprintf(buffer, " ac3 enable: %08x\n", - buf.rx.ac3_enable); - } - } - - quadlets = min_t(u32, sections[7], sizeof(buf.ext_sync) / 4); - if (quadlets >= 4) { - if (dice_proc_read_mem(dice, &buf.ext_sync, - sections[6], 4) < 0) - return; - snd_iprintf(buffer, "ext status:\n"); - snd_iprintf(buffer, " clock source: %s\n", - str_from_array(clock_sources, - ARRAY_SIZE(clock_sources), - buf.ext_sync.clock_source)); - snd_iprintf(buffer, " locked: %u\n", buf.ext_sync.locked); - snd_iprintf(buffer, " rate: %s\n", - str_from_array(rates, ARRAY_SIZE(rates), - buf.ext_sync.rate)); - snd_iprintf(buffer, " adat user data: "); - if (buf.ext_sync.adat_user_data & ADAT_USER_DATA_NO_DATA) - snd_iprintf(buffer, "-\n"); - else - snd_iprintf(buffer, "%x\n", - buf.ext_sync.adat_user_data); - } -} - -static void dice_create_proc(struct snd_dice *dice) -{ - struct snd_info_entry *entry; - - if (!snd_card_proc_new(dice->card, "dice", &entry)) - snd_info_set_text_ops(entry, dice, dice_proc_read); -} - #define OUI_WEISS 0x001c6a #define DICE_CATEGORY_ID 0x04 @@ -520,7 +278,7 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) if (err < 0) goto error; - dice_create_proc(dice); + snd_dice_create_proc(dice); err = snd_dice_stream_init(dice); if (err < 0) diff --git a/sound/firewire/dice/dice.h b/sound/firewire/dice/dice.h index dcc8c789cd43..969189a6604f 100644 --- a/sound/firewire/dice/dice.h +++ b/sound/firewire/dice/dice.h @@ -175,4 +175,6 @@ int snd_dice_create_pcm(struct snd_dice *dice); int snd_dice_create_hwdep(struct snd_dice *dice); +void snd_dice_create_proc(struct snd_dice *dice); + #endif -- cgit v1.2.3 From 2c2416c83e7345fc51af49132c40ec7d337d4132 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sat, 29 Nov 2014 00:59:18 +0900 Subject: ALSA: dice: Add new functions for constraints of PCM parameters This commit adds a new functions and some arrangement for PCM restriction. This arrangement is due to the number of channels which each Dice device has. I note that minimum number for period becomes 2, instead of 1 because its PCM functionality has SNDRV_PCM_INFO_BATCH, this means that the driver uses double (or more) buffering so the minimum number for period should be 2. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/dice/dice-pcm.c | 109 ++++++++++++++++++++++++----------------- 1 file changed, 65 insertions(+), 44 deletions(-) (limited to 'sound') diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c index deacb537eb81..2e531bd30e28 100644 --- a/sound/firewire/dice/dice-pcm.c +++ b/sound/firewire/dice/dice-pcm.c @@ -67,71 +67,92 @@ static int dice_channels_constraint(struct snd_pcm_hw_params *params, return snd_interval_refine(c, &channels); } - -static int pcm_open(struct snd_pcm_substream *substream) +static void limit_channels_and_rates(struct snd_dice *dice, + struct snd_pcm_runtime *runtime, + unsigned int *pcm_channels) { - static const struct snd_pcm_hardware hardware = { - .info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_BATCH | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER, - .formats = AMDTP_OUT_PCM_FORMAT_BITS, - .channels_min = UINT_MAX, - .channels_max = 0, - .buffer_bytes_max = 16 * 1024 * 1024, - .period_bytes_min = 1, - .period_bytes_max = UINT_MAX, - .periods_min = 1, - .periods_max = UINT_MAX, - }; - struct snd_dice *dice = substream->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; - unsigned int i; - int err; + struct snd_pcm_hardware *hw = &runtime->hw; + unsigned int i, rate, mode; - err = snd_dice_stream_lock_try(dice); - if (err < 0) - goto error; - - runtime->hw = hardware; + hw->channels_min = UINT_MAX; + hw->channels_max = 0; for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) { - if (dice->clock_caps & (1 << i)) - runtime->hw.rates |= - snd_pcm_rate_to_rate_bit(snd_dice_rates[i]); + rate = snd_dice_rates[i]; + if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0) + continue; + hw->rates |= snd_pcm_rate_to_rate_bit(rate); + + if (pcm_channels[mode] == 0) + continue; + hw->channels_min = min(hw->channels_min, pcm_channels[mode]); + hw->channels_max = max(hw->channels_max, pcm_channels[mode]); } + snd_pcm_limit_hw_rates(runtime); +} - for (i = 0; i < 3; ++i) { - if (dice->rx_channels[i]) { - runtime->hw.channels_min = min(runtime->hw.channels_min, - dice->rx_channels[i]); - runtime->hw.channels_max = max(runtime->hw.channels_max, - dice->rx_channels[i]); - } - } +static void limit_period_and_buffer(struct snd_pcm_hardware *hw) +{ + hw->periods_min = 2; /* SNDRV_PCM_INFO_BATCH */ + hw->periods_max = UINT_MAX; + + hw->period_bytes_min = 4 * hw->channels_max; /* byte for a frame */ + + /* Just to prevent from allocating much pages. */ + hw->period_bytes_max = hw->period_bytes_min * 2048; + hw->buffer_bytes_max = hw->period_bytes_max * hw->periods_min; +} + +static int init_hw_info(struct snd_dice *dice, + struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_pcm_hardware *hw = &runtime->hw; + int err; + + hw->info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_BATCH | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER; + hw->formats = AMDTP_OUT_PCM_FORMAT_BITS; + + limit_channels_and_rates(dice, runtime, dice->rx_channels); + limit_period_and_buffer(hw); err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, dice_rate_constraint, dice, SNDRV_PCM_HW_PARAM_CHANNELS, -1); if (err < 0) - goto err_lock; + goto end; err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, dice_channels_constraint, dice, SNDRV_PCM_HW_PARAM_RATE, -1); if (err < 0) - goto err_lock; + goto end; err = amdtp_stream_add_pcm_hw_constraints(&dice->rx_stream, runtime); - if (err < 0) - goto err_lock; +end: + return err; +} - return 0; +static int pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_dice *dice = substream->private_data; + int err; -err_lock: + err = snd_dice_stream_lock_try(dice); + if (err < 0) + goto end; + + err = init_hw_info(dice, substream); + if (err < 0) + goto err_locked; +end: + return err; +err_locked: snd_dice_stream_lock_release(dice); -error: return err; } -- cgit v1.2.3 From 60cea522963fc0b3893d78e568666d105f117ff9 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sat, 29 Nov 2014 00:59:24 +0900 Subject: ALSA: dice: remove experimental state Some developers test this driver, thus it's better to remove its experimental state. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig index 46dff64908c8..a433149f0675 100644 --- a/sound/firewire/Kconfig +++ b/sound/firewire/Kconfig @@ -13,12 +13,12 @@ config SND_FIREWIRE_LIB select SND_RAWMIDI config SND_DICE - tristate "DICE-based DACs (EXPERIMENTAL)" + tristate "DICE-based DACs support" select SND_HWDEP select SND_FIREWIRE_LIB help Say Y here to include support for many DACs based on the DICE - chip family (DICE-II/Jr/Mini) from TC Applied Technologies. + chip family (DICE-II/Jr/Mini) which TC Applied Technologies produces. At the moment, this driver supports playback only. If you want to use devices that support capturing, use FFADO instead. -- cgit v1.2.3 From 8832c5a74ba3506c51b6637ac78941fcd21afbef Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sat, 29 Nov 2014 00:59:25 +0900 Subject: ALSA: speakers: Rename to oxfw and rename some members This commit renames 'firewire-speakers' to 'oxfw' to enhance support for devices which based on OXFW970/971. A line for MODULE_ALIAS is added. Additionally, to help for works in followed paches, some members in private structure are renamed. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/Kconfig | 12 +- sound/firewire/Makefile | 4 +- sound/firewire/oxfw.c | 793 ++++++++++++++++++++++++++++++++++++++++++++++ sound/firewire/speakers.c | 792 --------------------------------------------- 4 files changed, 802 insertions(+), 799 deletions(-) create mode 100644 sound/firewire/oxfw.c delete mode 100644 sound/firewire/speakers.c (limited to 'sound') diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig index a433149f0675..2a5b9a6cb6f8 100644 --- a/sound/firewire/Kconfig +++ b/sound/firewire/Kconfig @@ -26,15 +26,17 @@ config SND_DICE To compile this driver as a module, choose M here: the module will be called snd-dice. -config SND_FIREWIRE_SPEAKERS - tristate "FireWire speakers" +config SND_OXFW + tristate "Oxford Semiconductor FW970/971 chipset support" select SND_FIREWIRE_LIB help - Say Y here to include support for the Griffin FireWave Surround - and the LaCie FireWire Speakers. + Say Y here to include support for FireWire devices based on + Oxford Semiconductor FW970/971 chipset. + * Griffin Firewave + * LaCie Firewire Speakers To compile this driver as a module, choose M here: the module - will be called snd-firewire-speakers. + will be called snd-oxfw. config SND_ISIGHT tristate "Apple iSight microphone" diff --git a/sound/firewire/Makefile b/sound/firewire/Makefile index c50761ccd66a..5ed6fb7bc979 100644 --- a/sound/firewire/Makefile +++ b/sound/firewire/Makefile @@ -1,12 +1,12 @@ snd-firewire-lib-objs := lib.o iso-resources.o packets-buffer.o \ fcp.o cmp.o amdtp.o -snd-firewire-speakers-objs := speakers.o +snd-oxfw-objs := oxfw.o snd-isight-objs := isight.o snd-scs1x-objs := scs1x.o obj-$(CONFIG_SND_FIREWIRE_LIB) += snd-firewire-lib.o obj-$(CONFIG_SND_DICE) += dice/ -obj-$(CONFIG_SND_FIREWIRE_SPEAKERS) += snd-firewire-speakers.o +obj-$(CONFIG_SND_OXFW) += snd-oxfw.o obj-$(CONFIG_SND_ISIGHT) += snd-isight.o obj-$(CONFIG_SND_SCS1X) += snd-scs1x.o obj-$(CONFIG_SND_FIREWORKS) += fireworks/ diff --git a/sound/firewire/oxfw.c b/sound/firewire/oxfw.c new file mode 100644 index 000000000000..b7498e9420d8 --- /dev/null +++ b/sound/firewire/oxfw.c @@ -0,0 +1,793 @@ +/* + * oxfw.c - a part of driver for OXFW970/971 based devices + * + * Copyright (c) Clemens Ladisch + * Licensed under the terms of the GNU General Public License, version 2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cmp.h" +#include "fcp.h" +#include "amdtp.h" +#include "lib.h" + +#define OXFORD_FIRMWARE_ID_ADDRESS (CSR_REGISTER_BASE + 0x50000) +/* 0x970?vvvv or 0x971?vvvv, where vvvv = firmware version */ + +#define OXFORD_HARDWARE_ID_ADDRESS (CSR_REGISTER_BASE + 0x90020) +#define OXFORD_HARDWARE_ID_OXFW970 0x39443841 +#define OXFORD_HARDWARE_ID_OXFW971 0x39373100 + +#define VENDOR_GRIFFIN 0x001292 +#define VENDOR_LACIE 0x00d04b + +#define SPECIFIER_1394TA 0x00a02d +#define VERSION_AVC 0x010001 + +struct device_info { + const char *driver_name; + const char *short_name; + const char *long_name; + int (*pcm_constraints)(struct snd_pcm_runtime *runtime); + unsigned int mixer_channels; + u8 mute_fb_id; + u8 volume_fb_id; +}; + +struct snd_oxfw { + struct snd_card *card; + struct fw_unit *unit; + const struct device_info *device_info; + struct mutex mutex; + struct cmp_connection in_conn; + struct amdtp_stream rx_stream; + bool mute; + s16 volume[6]; + s16 volume_min; + s16 volume_max; +}; + +MODULE_DESCRIPTION("Oxford Semiconductor FW970/971 driver"); +MODULE_AUTHOR("Clemens Ladisch "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("snd-firewire-speakers"); + +static int firewave_rate_constraint(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + static unsigned int stereo_rates[] = { 48000, 96000 }; + struct snd_interval *channels = + hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_interval *rate = + hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + + /* two channels work only at 48/96 kHz */ + if (snd_interval_max(channels) < 6) + return snd_interval_list(rate, 2, stereo_rates, 0); + return 0; +} + +static int firewave_channels_constraint(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + static const struct snd_interval all_channels = { .min = 6, .max = 6 }; + struct snd_interval *rate = + hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = + hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + + /* 32/44.1 kHz work only with all six channels */ + if (snd_interval_max(rate) < 48000) + return snd_interval_refine(channels, &all_channels); + return 0; +} + +static int firewave_constraints(struct snd_pcm_runtime *runtime) +{ + static unsigned int channels_list[] = { 2, 6 }; + static struct snd_pcm_hw_constraint_list channels_list_constraint = { + .count = 2, + .list = channels_list, + }; + int err; + + runtime->hw.rates = SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_96000; + runtime->hw.channels_max = 6; + + err = snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, + &channels_list_constraint); + if (err < 0) + return err; + err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + firewave_rate_constraint, NULL, + SNDRV_PCM_HW_PARAM_CHANNELS, -1); + if (err < 0) + return err; + err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + firewave_channels_constraint, NULL, + SNDRV_PCM_HW_PARAM_RATE, -1); + if (err < 0) + return err; + + return 0; +} + +static int lacie_speakers_constraints(struct snd_pcm_runtime *runtime) +{ + runtime->hw.rates = SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000; + + return 0; +} + +static int oxfw_open(struct snd_pcm_substream *substream) +{ + static const struct snd_pcm_hardware hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_BATCH | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER, + .formats = AMDTP_OUT_PCM_FORMAT_BITS, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 4 * 1024 * 1024, + .period_bytes_min = 1, + .period_bytes_max = UINT_MAX, + .periods_min = 1, + .periods_max = UINT_MAX, + }; + struct snd_oxfw *oxfw = substream->private_data; + struct snd_pcm_runtime *runtime = substream->runtime; + int err; + + runtime->hw = hardware; + + err = oxfw->device_info->pcm_constraints(runtime); + if (err < 0) + return err; + err = snd_pcm_limit_hw_rates(runtime); + if (err < 0) + return err; + + err = amdtp_stream_add_pcm_hw_constraints(&oxfw->rx_stream, runtime); + if (err < 0) + return err; + + return 0; +} + +static int oxfw_close(struct snd_pcm_substream *substream) +{ + return 0; +} + +static void oxfw_stop_stream(struct snd_oxfw *oxfw) +{ + if (amdtp_stream_running(&oxfw->rx_stream)) { + amdtp_stream_stop(&oxfw->rx_stream); + cmp_connection_break(&oxfw->in_conn); + } +} + +static int oxfw_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct snd_oxfw *oxfw = substream->private_data; + int err; + + mutex_lock(&oxfw->mutex); + oxfw_stop_stream(oxfw); + mutex_unlock(&oxfw->mutex); + + err = snd_pcm_lib_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); + if (err < 0) + goto error; + + amdtp_stream_set_parameters(&oxfw->rx_stream, + params_rate(hw_params), + params_channels(hw_params), + 0); + + amdtp_stream_set_pcm_format(&oxfw->rx_stream, + params_format(hw_params)); + + err = avc_general_set_sig_fmt(oxfw->unit, params_rate(hw_params), + AVC_GENERAL_PLUG_DIR_IN, 0); + if (err < 0) { + dev_err(&oxfw->unit->device, "failed to set sample rate\n"); + goto err_buffer; + } + + return 0; + +err_buffer: + snd_pcm_lib_free_vmalloc_buffer(substream); +error: + return err; +} + +static int oxfw_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_oxfw *oxfw = substream->private_data; + + mutex_lock(&oxfw->mutex); + oxfw_stop_stream(oxfw); + mutex_unlock(&oxfw->mutex); + + return snd_pcm_lib_free_vmalloc_buffer(substream); +} + +static int oxfw_prepare(struct snd_pcm_substream *substream) +{ + struct snd_oxfw *oxfw = substream->private_data; + int err; + + mutex_lock(&oxfw->mutex); + + if (amdtp_streaming_error(&oxfw->rx_stream)) + oxfw_stop_stream(oxfw); + + if (!amdtp_stream_running(&oxfw->rx_stream)) { + err = cmp_connection_establish(&oxfw->in_conn, + amdtp_stream_get_max_payload(&oxfw->rx_stream)); + if (err < 0) + goto err_mutex; + + err = amdtp_stream_start(&oxfw->rx_stream, + oxfw->in_conn.resources.channel, + oxfw->in_conn.speed); + if (err < 0) + goto err_connection; + } + + mutex_unlock(&oxfw->mutex); + + amdtp_stream_pcm_prepare(&oxfw->rx_stream); + + return 0; + +err_connection: + cmp_connection_break(&oxfw->in_conn); +err_mutex: + mutex_unlock(&oxfw->mutex); + + return err; +} + +static int oxfw_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_oxfw *oxfw = substream->private_data; + struct snd_pcm_substream *pcm; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + pcm = substream; + break; + case SNDRV_PCM_TRIGGER_STOP: + pcm = NULL; + break; + default: + return -EINVAL; + } + amdtp_stream_pcm_trigger(&oxfw->rx_stream, pcm); + return 0; +} + +static snd_pcm_uframes_t oxfw_pointer(struct snd_pcm_substream *substream) +{ + struct snd_oxfw *oxfw = substream->private_data; + + return amdtp_stream_pcm_pointer(&oxfw->rx_stream); +} + +static int oxfw_create_pcm(struct snd_oxfw *oxfw) +{ + static struct snd_pcm_ops ops = { + .open = oxfw_open, + .close = oxfw_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = oxfw_hw_params, + .hw_free = oxfw_hw_free, + .prepare = oxfw_prepare, + .trigger = oxfw_trigger, + .pointer = oxfw_pointer, + .page = snd_pcm_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, + }; + struct snd_pcm *pcm; + int err; + + err = snd_pcm_new(oxfw->card, "OXFW", 0, 1, 0, &pcm); + if (err < 0) + return err; + pcm->private_data = oxfw; + strcpy(pcm->name, oxfw->device_info->short_name); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ops); + return 0; +} + +enum control_action { CTL_READ, CTL_WRITE }; +enum control_attribute { + CTL_MIN = 0x02, + CTL_MAX = 0x03, + CTL_CURRENT = 0x10, +}; + +static int oxfw_mute_command(struct snd_oxfw *oxfw, bool *value, + enum control_action action) +{ + u8 *buf; + u8 response_ok; + int err; + + buf = kmalloc(11, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (action == CTL_READ) { + buf[0] = 0x01; /* AV/C, STATUS */ + response_ok = 0x0c; /* STABLE */ + } else { + buf[0] = 0x00; /* AV/C, CONTROL */ + response_ok = 0x09; /* ACCEPTED */ + } + buf[1] = 0x08; /* audio unit 0 */ + buf[2] = 0xb8; /* FUNCTION BLOCK */ + buf[3] = 0x81; /* function block type: feature */ + buf[4] = oxfw->device_info->mute_fb_id; /* function block ID */ + buf[5] = 0x10; /* control attribute: current */ + buf[6] = 0x02; /* selector length */ + buf[7] = 0x00; /* audio channel number */ + buf[8] = 0x01; /* control selector: mute */ + buf[9] = 0x01; /* control data length */ + if (action == CTL_READ) + buf[10] = 0xff; + else + buf[10] = *value ? 0x70 : 0x60; + + err = fcp_avc_transaction(oxfw->unit, buf, 11, buf, 11, 0x3fe); + if (err < 0) + goto error; + if (err < 11) { + dev_err(&oxfw->unit->device, "short FCP response\n"); + err = -EIO; + goto error; + } + if (buf[0] != response_ok) { + dev_err(&oxfw->unit->device, "mute command failed\n"); + err = -EIO; + goto error; + } + if (action == CTL_READ) + *value = buf[10] == 0x70; + + err = 0; + +error: + kfree(buf); + + return err; +} + +static int oxfw_volume_command(struct snd_oxfw *oxfw, s16 *value, + unsigned int channel, + enum control_attribute attribute, + enum control_action action) +{ + u8 *buf; + u8 response_ok; + int err; + + buf = kmalloc(12, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (action == CTL_READ) { + buf[0] = 0x01; /* AV/C, STATUS */ + response_ok = 0x0c; /* STABLE */ + } else { + buf[0] = 0x00; /* AV/C, CONTROL */ + response_ok = 0x09; /* ACCEPTED */ + } + buf[1] = 0x08; /* audio unit 0 */ + buf[2] = 0xb8; /* FUNCTION BLOCK */ + buf[3] = 0x81; /* function block type: feature */ + buf[4] = oxfw->device_info->volume_fb_id; /* function block ID */ + buf[5] = attribute; /* control attribute */ + buf[6] = 0x02; /* selector length */ + buf[7] = channel; /* audio channel number */ + buf[8] = 0x02; /* control selector: volume */ + buf[9] = 0x02; /* control data length */ + if (action == CTL_READ) { + buf[10] = 0xff; + buf[11] = 0xff; + } else { + buf[10] = *value >> 8; + buf[11] = *value; + } + + err = fcp_avc_transaction(oxfw->unit, buf, 12, buf, 12, 0x3fe); + if (err < 0) + goto error; + if (err < 12) { + dev_err(&oxfw->unit->device, "short FCP response\n"); + err = -EIO; + goto error; + } + if (buf[0] != response_ok) { + dev_err(&oxfw->unit->device, "volume command failed\n"); + err = -EIO; + goto error; + } + if (action == CTL_READ) + *value = (buf[10] << 8) | buf[11]; + + err = 0; + +error: + kfree(buf); + + return err; +} + +static int oxfw_mute_get(struct snd_kcontrol *control, + struct snd_ctl_elem_value *value) +{ + struct snd_oxfw *oxfw = control->private_data; + + value->value.integer.value[0] = !oxfw->mute; + + return 0; +} + +static int oxfw_mute_put(struct snd_kcontrol *control, + struct snd_ctl_elem_value *value) +{ + struct snd_oxfw *oxfw = control->private_data; + bool mute; + int err; + + mute = !value->value.integer.value[0]; + + if (mute == oxfw->mute) + return 0; + + err = oxfw_mute_command(oxfw, &mute, CTL_WRITE); + if (err < 0) + return err; + oxfw->mute = mute; + + return 1; +} + +static int oxfw_volume_info(struct snd_kcontrol *control, + struct snd_ctl_elem_info *info) +{ + struct snd_oxfw *oxfw = control->private_data; + + info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + info->count = oxfw->device_info->mixer_channels; + info->value.integer.min = oxfw->volume_min; + info->value.integer.max = oxfw->volume_max; + + return 0; +} + +static const u8 channel_map[6] = { 0, 1, 4, 5, 2, 3 }; + +static int oxfw_volume_get(struct snd_kcontrol *control, + struct snd_ctl_elem_value *value) +{ + struct snd_oxfw *oxfw = control->private_data; + unsigned int i; + + for (i = 0; i < oxfw->device_info->mixer_channels; ++i) + value->value.integer.value[channel_map[i]] = oxfw->volume[i]; + + return 0; +} + +static int oxfw_volume_put(struct snd_kcontrol *control, + struct snd_ctl_elem_value *value) +{ + struct snd_oxfw *oxfw = control->private_data; + unsigned int i, changed_channels; + bool equal_values = true; + s16 volume; + int err; + + for (i = 0; i < oxfw->device_info->mixer_channels; ++i) { + if (value->value.integer.value[i] < oxfw->volume_min || + value->value.integer.value[i] > oxfw->volume_max) + return -EINVAL; + if (value->value.integer.value[i] != + value->value.integer.value[0]) + equal_values = false; + } + + changed_channels = 0; + for (i = 0; i < oxfw->device_info->mixer_channels; ++i) + if (value->value.integer.value[channel_map[i]] != + oxfw->volume[i]) + changed_channels |= 1 << (i + 1); + + if (equal_values && changed_channels != 0) + changed_channels = 1 << 0; + + for (i = 0; i <= oxfw->device_info->mixer_channels; ++i) { + volume = value->value.integer.value[channel_map[i ? i - 1 : 0]]; + if (changed_channels & (1 << i)) { + err = oxfw_volume_command(oxfw, &volume, i, + CTL_CURRENT, CTL_WRITE); + if (err < 0) + return err; + } + if (i > 0) + oxfw->volume[i - 1] = volume; + } + + return changed_channels != 0; +} + +static int oxfw_create_mixer(struct snd_oxfw *oxfw) +{ + static const struct snd_kcontrol_new controls[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "PCM Playback Switch", + .info = snd_ctl_boolean_mono_info, + .get = oxfw_mute_get, + .put = oxfw_mute_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "PCM Playback Volume", + .info = oxfw_volume_info, + .get = oxfw_volume_get, + .put = oxfw_volume_put, + }, + }; + unsigned int i, first_ch; + int err; + + err = oxfw_volume_command(oxfw, &oxfw->volume_min, + 0, CTL_MIN, CTL_READ); + if (err < 0) + return err; + err = oxfw_volume_command(oxfw, &oxfw->volume_max, + 0, CTL_MAX, CTL_READ); + if (err < 0) + return err; + + err = oxfw_mute_command(oxfw, &oxfw->mute, CTL_READ); + if (err < 0) + return err; + + first_ch = oxfw->device_info->mixer_channels == 1 ? 0 : 1; + for (i = 0; i < oxfw->device_info->mixer_channels; ++i) { + err = oxfw_volume_command(oxfw, &oxfw->volume[i], + first_ch + i, CTL_CURRENT, CTL_READ); + if (err < 0) + return err; + } + + for (i = 0; i < ARRAY_SIZE(controls); ++i) { + err = snd_ctl_add(oxfw->card, + snd_ctl_new1(&controls[i], oxfw)); + if (err < 0) + return err; + } + + return 0; +} + +static u32 oxfw_read_firmware_version(struct fw_unit *unit) +{ + __be32 data; + int err; + + err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST, + OXFORD_FIRMWARE_ID_ADDRESS, &data, 4, 0); + return err >= 0 ? be32_to_cpu(data) : 0; +} + +static void oxfw_card_free(struct snd_card *card) +{ + struct snd_oxfw *oxfw = card->private_data; + + amdtp_stream_destroy(&oxfw->rx_stream); + cmp_connection_destroy(&oxfw->in_conn); + fw_unit_put(oxfw->unit); + mutex_destroy(&oxfw->mutex); +} + +static int oxfw_probe(struct fw_unit *unit, + const struct ieee1394_device_id *id) +{ + struct fw_device *fw_dev = fw_parent_device(unit); + struct snd_card *card; + struct snd_oxfw *oxfw; + u32 firmware; + int err; + + err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, + sizeof(*oxfw), &card); + if (err < 0) + return err; + + oxfw = card->private_data; + oxfw->card = card; + mutex_init(&oxfw->mutex); + oxfw->unit = fw_unit_get(unit); + oxfw->device_info = (const struct device_info *)id->driver_data; + + err = cmp_connection_init(&oxfw->in_conn, unit, CMP_INPUT, 0); + if (err < 0) + goto err_unit; + + err = amdtp_stream_init(&oxfw->rx_stream, unit, AMDTP_OUT_STREAM, + CIP_NONBLOCKING); + if (err < 0) + goto err_connection; + + card->private_free = oxfw_card_free; + + strcpy(card->driver, oxfw->device_info->driver_name); + strcpy(card->shortname, oxfw->device_info->short_name); + firmware = oxfw_read_firmware_version(unit); + snprintf(card->longname, sizeof(card->longname), + "%s (OXFW%x %04x), GUID %08x%08x at %s, S%d", + oxfw->device_info->long_name, + firmware >> 20, firmware & 0xffff, + fw_dev->config_rom[3], fw_dev->config_rom[4], + dev_name(&unit->device), 100 << fw_dev->max_speed); + strcpy(card->mixername, "OXFW"); + + err = oxfw_create_pcm(oxfw); + if (err < 0) + goto error; + + err = oxfw_create_mixer(oxfw); + if (err < 0) + goto error; + + err = snd_card_register(card); + if (err < 0) + goto error; + + dev_set_drvdata(&unit->device, oxfw); + + return 0; + +err_connection: + cmp_connection_destroy(&oxfw->in_conn); +err_unit: + fw_unit_put(oxfw->unit); + mutex_destroy(&oxfw->mutex); +error: + snd_card_free(card); + return err; +} + +static void oxfw_bus_reset(struct fw_unit *unit) +{ + struct snd_oxfw *oxfw = dev_get_drvdata(&unit->device); + + fcp_bus_reset(oxfw->unit); + + if (cmp_connection_update(&oxfw->in_conn) < 0) { + amdtp_stream_pcm_abort(&oxfw->rx_stream); + mutex_lock(&oxfw->mutex); + oxfw_stop_stream(oxfw); + mutex_unlock(&oxfw->mutex); + return; + } + + amdtp_stream_update(&oxfw->rx_stream); +} + +static void oxfw_remove(struct fw_unit *unit) +{ + struct snd_oxfw *oxfw = dev_get_drvdata(&unit->device); + + amdtp_stream_pcm_abort(&oxfw->rx_stream); + snd_card_disconnect(oxfw->card); + + mutex_lock(&oxfw->mutex); + oxfw_stop_stream(oxfw); + mutex_unlock(&oxfw->mutex); + + snd_card_free_when_closed(oxfw->card); +} + +static const struct device_info griffin_firewave = { + .driver_name = "FireWave", + .short_name = "FireWave", + .long_name = "Griffin FireWave Surround", + .pcm_constraints = firewave_constraints, + .mixer_channels = 6, + .mute_fb_id = 0x01, + .volume_fb_id = 0x02, +}; + +static const struct device_info lacie_speakers = { + .driver_name = "FWSpeakers", + .short_name = "FireWire Speakers", + .long_name = "LaCie FireWire Speakers", + .pcm_constraints = lacie_speakers_constraints, + .mixer_channels = 1, + .mute_fb_id = 0x01, + .volume_fb_id = 0x01, +}; + +static const struct ieee1394_device_id oxfw_id_table[] = { + { + .match_flags = IEEE1394_MATCH_VENDOR_ID | + IEEE1394_MATCH_MODEL_ID | + IEEE1394_MATCH_SPECIFIER_ID | + IEEE1394_MATCH_VERSION, + .vendor_id = VENDOR_GRIFFIN, + .model_id = 0x00f970, + .specifier_id = SPECIFIER_1394TA, + .version = VERSION_AVC, + .driver_data = (kernel_ulong_t)&griffin_firewave, + }, + { + .match_flags = IEEE1394_MATCH_VENDOR_ID | + IEEE1394_MATCH_MODEL_ID | + IEEE1394_MATCH_SPECIFIER_ID | + IEEE1394_MATCH_VERSION, + .vendor_id = VENDOR_LACIE, + .model_id = 0x00f970, + .specifier_id = SPECIFIER_1394TA, + .version = VERSION_AVC, + .driver_data = (kernel_ulong_t)&lacie_speakers, + }, + { } +}; +MODULE_DEVICE_TABLE(ieee1394, oxfw_id_table); + +static struct fw_driver oxfw_driver = { + .driver = { + .owner = THIS_MODULE, + .name = KBUILD_MODNAME, + .bus = &fw_bus_type, + }, + .probe = oxfw_probe, + .update = oxfw_bus_reset, + .remove = oxfw_remove, + .id_table = oxfw_id_table, +}; + +static int __init snd_oxfw_init(void) +{ + return driver_register(&oxfw_driver.driver); +} + +static void __exit snd_oxfw_exit(void) +{ + driver_unregister(&oxfw_driver.driver); +} + +module_init(snd_oxfw_init); +module_exit(snd_oxfw_exit); diff --git a/sound/firewire/speakers.c b/sound/firewire/speakers.c deleted file mode 100644 index 768d40ddfebb..000000000000 --- a/sound/firewire/speakers.c +++ /dev/null @@ -1,792 +0,0 @@ -/* - * OXFW970-based speakers driver - * - * Copyright (c) Clemens Ladisch - * Licensed under the terms of the GNU General Public License, version 2. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "cmp.h" -#include "fcp.h" -#include "amdtp.h" -#include "lib.h" - -#define OXFORD_FIRMWARE_ID_ADDRESS (CSR_REGISTER_BASE + 0x50000) -/* 0x970?vvvv or 0x971?vvvv, where vvvv = firmware version */ - -#define OXFORD_HARDWARE_ID_ADDRESS (CSR_REGISTER_BASE + 0x90020) -#define OXFORD_HARDWARE_ID_OXFW970 0x39443841 -#define OXFORD_HARDWARE_ID_OXFW971 0x39373100 - -#define VENDOR_GRIFFIN 0x001292 -#define VENDOR_LACIE 0x00d04b - -#define SPECIFIER_1394TA 0x00a02d -#define VERSION_AVC 0x010001 - -struct device_info { - const char *driver_name; - const char *short_name; - const char *long_name; - int (*pcm_constraints)(struct snd_pcm_runtime *runtime); - unsigned int mixer_channels; - u8 mute_fb_id; - u8 volume_fb_id; -}; - -struct fwspk { - struct snd_card *card; - struct fw_unit *unit; - const struct device_info *device_info; - struct mutex mutex; - struct cmp_connection connection; - struct amdtp_stream stream; - bool mute; - s16 volume[6]; - s16 volume_min; - s16 volume_max; -}; - -MODULE_DESCRIPTION("FireWire speakers driver"); -MODULE_AUTHOR("Clemens Ladisch "); -MODULE_LICENSE("GPL v2"); - -static int firewave_rate_constraint(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - static unsigned int stereo_rates[] = { 48000, 96000 }; - struct snd_interval *channels = - hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_interval *rate = - hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); - - /* two channels work only at 48/96 kHz */ - if (snd_interval_max(channels) < 6) - return snd_interval_list(rate, 2, stereo_rates, 0); - return 0; -} - -static int firewave_channels_constraint(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - static const struct snd_interval all_channels = { .min = 6, .max = 6 }; - struct snd_interval *rate = - hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *channels = - hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - - /* 32/44.1 kHz work only with all six channels */ - if (snd_interval_max(rate) < 48000) - return snd_interval_refine(channels, &all_channels); - return 0; -} - -static int firewave_constraints(struct snd_pcm_runtime *runtime) -{ - static unsigned int channels_list[] = { 2, 6 }; - static struct snd_pcm_hw_constraint_list channels_list_constraint = { - .count = 2, - .list = channels_list, - }; - int err; - - runtime->hw.rates = SNDRV_PCM_RATE_32000 | - SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_96000; - runtime->hw.channels_max = 6; - - err = snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, - &channels_list_constraint); - if (err < 0) - return err; - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - firewave_rate_constraint, NULL, - SNDRV_PCM_HW_PARAM_CHANNELS, -1); - if (err < 0) - return err; - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - firewave_channels_constraint, NULL, - SNDRV_PCM_HW_PARAM_RATE, -1); - if (err < 0) - return err; - - return 0; -} - -static int lacie_speakers_constraints(struct snd_pcm_runtime *runtime) -{ - runtime->hw.rates = SNDRV_PCM_RATE_32000 | - SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_88200 | - SNDRV_PCM_RATE_96000; - - return 0; -} - -static int fwspk_open(struct snd_pcm_substream *substream) -{ - static const struct snd_pcm_hardware hardware = { - .info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_BATCH | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER, - .formats = AMDTP_OUT_PCM_FORMAT_BITS, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = 4 * 1024 * 1024, - .period_bytes_min = 1, - .period_bytes_max = UINT_MAX, - .periods_min = 1, - .periods_max = UINT_MAX, - }; - struct fwspk *fwspk = substream->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; - int err; - - runtime->hw = hardware; - - err = fwspk->device_info->pcm_constraints(runtime); - if (err < 0) - return err; - err = snd_pcm_limit_hw_rates(runtime); - if (err < 0) - return err; - - err = amdtp_stream_add_pcm_hw_constraints(&fwspk->stream, runtime); - if (err < 0) - return err; - - return 0; -} - -static int fwspk_close(struct snd_pcm_substream *substream) -{ - return 0; -} - -static void fwspk_stop_stream(struct fwspk *fwspk) -{ - if (amdtp_stream_running(&fwspk->stream)) { - amdtp_stream_stop(&fwspk->stream); - cmp_connection_break(&fwspk->connection); - } -} - -static int fwspk_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct fwspk *fwspk = substream->private_data; - int err; - - mutex_lock(&fwspk->mutex); - fwspk_stop_stream(fwspk); - mutex_unlock(&fwspk->mutex); - - err = snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); - if (err < 0) - goto error; - - amdtp_stream_set_parameters(&fwspk->stream, - params_rate(hw_params), - params_channels(hw_params), - 0); - - amdtp_stream_set_pcm_format(&fwspk->stream, - params_format(hw_params)); - - err = avc_general_set_sig_fmt(fwspk->unit, params_rate(hw_params), - AVC_GENERAL_PLUG_DIR_IN, 0); - if (err < 0) { - dev_err(&fwspk->unit->device, "failed to set sample rate\n"); - goto err_buffer; - } - - return 0; - -err_buffer: - snd_pcm_lib_free_vmalloc_buffer(substream); -error: - return err; -} - -static int fwspk_hw_free(struct snd_pcm_substream *substream) -{ - struct fwspk *fwspk = substream->private_data; - - mutex_lock(&fwspk->mutex); - fwspk_stop_stream(fwspk); - mutex_unlock(&fwspk->mutex); - - return snd_pcm_lib_free_vmalloc_buffer(substream); -} - -static int fwspk_prepare(struct snd_pcm_substream *substream) -{ - struct fwspk *fwspk = substream->private_data; - int err; - - mutex_lock(&fwspk->mutex); - - if (amdtp_streaming_error(&fwspk->stream)) - fwspk_stop_stream(fwspk); - - if (!amdtp_stream_running(&fwspk->stream)) { - err = cmp_connection_establish(&fwspk->connection, - amdtp_stream_get_max_payload(&fwspk->stream)); - if (err < 0) - goto err_mutex; - - err = amdtp_stream_start(&fwspk->stream, - fwspk->connection.resources.channel, - fwspk->connection.speed); - if (err < 0) - goto err_connection; - } - - mutex_unlock(&fwspk->mutex); - - amdtp_stream_pcm_prepare(&fwspk->stream); - - return 0; - -err_connection: - cmp_connection_break(&fwspk->connection); -err_mutex: - mutex_unlock(&fwspk->mutex); - - return err; -} - -static int fwspk_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct fwspk *fwspk = substream->private_data; - struct snd_pcm_substream *pcm; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - pcm = substream; - break; - case SNDRV_PCM_TRIGGER_STOP: - pcm = NULL; - break; - default: - return -EINVAL; - } - amdtp_stream_pcm_trigger(&fwspk->stream, pcm); - return 0; -} - -static snd_pcm_uframes_t fwspk_pointer(struct snd_pcm_substream *substream) -{ - struct fwspk *fwspk = substream->private_data; - - return amdtp_stream_pcm_pointer(&fwspk->stream); -} - -static int fwspk_create_pcm(struct fwspk *fwspk) -{ - static struct snd_pcm_ops ops = { - .open = fwspk_open, - .close = fwspk_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = fwspk_hw_params, - .hw_free = fwspk_hw_free, - .prepare = fwspk_prepare, - .trigger = fwspk_trigger, - .pointer = fwspk_pointer, - .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, - }; - struct snd_pcm *pcm; - int err; - - err = snd_pcm_new(fwspk->card, "OXFW970", 0, 1, 0, &pcm); - if (err < 0) - return err; - pcm->private_data = fwspk; - strcpy(pcm->name, fwspk->device_info->short_name); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ops); - return 0; -} - -enum control_action { CTL_READ, CTL_WRITE }; -enum control_attribute { - CTL_MIN = 0x02, - CTL_MAX = 0x03, - CTL_CURRENT = 0x10, -}; - -static int fwspk_mute_command(struct fwspk *fwspk, bool *value, - enum control_action action) -{ - u8 *buf; - u8 response_ok; - int err; - - buf = kmalloc(11, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - if (action == CTL_READ) { - buf[0] = 0x01; /* AV/C, STATUS */ - response_ok = 0x0c; /* STABLE */ - } else { - buf[0] = 0x00; /* AV/C, CONTROL */ - response_ok = 0x09; /* ACCEPTED */ - } - buf[1] = 0x08; /* audio unit 0 */ - buf[2] = 0xb8; /* FUNCTION BLOCK */ - buf[3] = 0x81; /* function block type: feature */ - buf[4] = fwspk->device_info->mute_fb_id; /* function block ID */ - buf[5] = 0x10; /* control attribute: current */ - buf[6] = 0x02; /* selector length */ - buf[7] = 0x00; /* audio channel number */ - buf[8] = 0x01; /* control selector: mute */ - buf[9] = 0x01; /* control data length */ - if (action == CTL_READ) - buf[10] = 0xff; - else - buf[10] = *value ? 0x70 : 0x60; - - err = fcp_avc_transaction(fwspk->unit, buf, 11, buf, 11, 0x3fe); - if (err < 0) - goto error; - if (err < 11) { - dev_err(&fwspk->unit->device, "short FCP response\n"); - err = -EIO; - goto error; - } - if (buf[0] != response_ok) { - dev_err(&fwspk->unit->device, "mute command failed\n"); - err = -EIO; - goto error; - } - if (action == CTL_READ) - *value = buf[10] == 0x70; - - err = 0; - -error: - kfree(buf); - - return err; -} - -static int fwspk_volume_command(struct fwspk *fwspk, s16 *value, - unsigned int channel, - enum control_attribute attribute, - enum control_action action) -{ - u8 *buf; - u8 response_ok; - int err; - - buf = kmalloc(12, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - if (action == CTL_READ) { - buf[0] = 0x01; /* AV/C, STATUS */ - response_ok = 0x0c; /* STABLE */ - } else { - buf[0] = 0x00; /* AV/C, CONTROL */ - response_ok = 0x09; /* ACCEPTED */ - } - buf[1] = 0x08; /* audio unit 0 */ - buf[2] = 0xb8; /* FUNCTION BLOCK */ - buf[3] = 0x81; /* function block type: feature */ - buf[4] = fwspk->device_info->volume_fb_id; /* function block ID */ - buf[5] = attribute; /* control attribute */ - buf[6] = 0x02; /* selector length */ - buf[7] = channel; /* audio channel number */ - buf[8] = 0x02; /* control selector: volume */ - buf[9] = 0x02; /* control data length */ - if (action == CTL_READ) { - buf[10] = 0xff; - buf[11] = 0xff; - } else { - buf[10] = *value >> 8; - buf[11] = *value; - } - - err = fcp_avc_transaction(fwspk->unit, buf, 12, buf, 12, 0x3fe); - if (err < 0) - goto error; - if (err < 12) { - dev_err(&fwspk->unit->device, "short FCP response\n"); - err = -EIO; - goto error; - } - if (buf[0] != response_ok) { - dev_err(&fwspk->unit->device, "volume command failed\n"); - err = -EIO; - goto error; - } - if (action == CTL_READ) - *value = (buf[10] << 8) | buf[11]; - - err = 0; - -error: - kfree(buf); - - return err; -} - -static int fwspk_mute_get(struct snd_kcontrol *control, - struct snd_ctl_elem_value *value) -{ - struct fwspk *fwspk = control->private_data; - - value->value.integer.value[0] = !fwspk->mute; - - return 0; -} - -static int fwspk_mute_put(struct snd_kcontrol *control, - struct snd_ctl_elem_value *value) -{ - struct fwspk *fwspk = control->private_data; - bool mute; - int err; - - mute = !value->value.integer.value[0]; - - if (mute == fwspk->mute) - return 0; - - err = fwspk_mute_command(fwspk, &mute, CTL_WRITE); - if (err < 0) - return err; - fwspk->mute = mute; - - return 1; -} - -static int fwspk_volume_info(struct snd_kcontrol *control, - struct snd_ctl_elem_info *info) -{ - struct fwspk *fwspk = control->private_data; - - info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - info->count = fwspk->device_info->mixer_channels; - info->value.integer.min = fwspk->volume_min; - info->value.integer.max = fwspk->volume_max; - - return 0; -} - -static const u8 channel_map[6] = { 0, 1, 4, 5, 2, 3 }; - -static int fwspk_volume_get(struct snd_kcontrol *control, - struct snd_ctl_elem_value *value) -{ - struct fwspk *fwspk = control->private_data; - unsigned int i; - - for (i = 0; i < fwspk->device_info->mixer_channels; ++i) - value->value.integer.value[channel_map[i]] = fwspk->volume[i]; - - return 0; -} - -static int fwspk_volume_put(struct snd_kcontrol *control, - struct snd_ctl_elem_value *value) -{ - struct fwspk *fwspk = control->private_data; - unsigned int i, changed_channels; - bool equal_values = true; - s16 volume; - int err; - - for (i = 0; i < fwspk->device_info->mixer_channels; ++i) { - if (value->value.integer.value[i] < fwspk->volume_min || - value->value.integer.value[i] > fwspk->volume_max) - return -EINVAL; - if (value->value.integer.value[i] != - value->value.integer.value[0]) - equal_values = false; - } - - changed_channels = 0; - for (i = 0; i < fwspk->device_info->mixer_channels; ++i) - if (value->value.integer.value[channel_map[i]] != - fwspk->volume[i]) - changed_channels |= 1 << (i + 1); - - if (equal_values && changed_channels != 0) - changed_channels = 1 << 0; - - for (i = 0; i <= fwspk->device_info->mixer_channels; ++i) { - volume = value->value.integer.value[channel_map[i ? i - 1 : 0]]; - if (changed_channels & (1 << i)) { - err = fwspk_volume_command(fwspk, &volume, i, - CTL_CURRENT, CTL_WRITE); - if (err < 0) - return err; - } - if (i > 0) - fwspk->volume[i - 1] = volume; - } - - return changed_channels != 0; -} - -static int fwspk_create_mixer(struct fwspk *fwspk) -{ - static const struct snd_kcontrol_new controls[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Playback Switch", - .info = snd_ctl_boolean_mono_info, - .get = fwspk_mute_get, - .put = fwspk_mute_put, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Playback Volume", - .info = fwspk_volume_info, - .get = fwspk_volume_get, - .put = fwspk_volume_put, - }, - }; - unsigned int i, first_ch; - int err; - - err = fwspk_volume_command(fwspk, &fwspk->volume_min, - 0, CTL_MIN, CTL_READ); - if (err < 0) - return err; - err = fwspk_volume_command(fwspk, &fwspk->volume_max, - 0, CTL_MAX, CTL_READ); - if (err < 0) - return err; - - err = fwspk_mute_command(fwspk, &fwspk->mute, CTL_READ); - if (err < 0) - return err; - - first_ch = fwspk->device_info->mixer_channels == 1 ? 0 : 1; - for (i = 0; i < fwspk->device_info->mixer_channels; ++i) { - err = fwspk_volume_command(fwspk, &fwspk->volume[i], - first_ch + i, CTL_CURRENT, CTL_READ); - if (err < 0) - return err; - } - - for (i = 0; i < ARRAY_SIZE(controls); ++i) { - err = snd_ctl_add(fwspk->card, - snd_ctl_new1(&controls[i], fwspk)); - if (err < 0) - return err; - } - - return 0; -} - -static u32 fwspk_read_firmware_version(struct fw_unit *unit) -{ - __be32 data; - int err; - - err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST, - OXFORD_FIRMWARE_ID_ADDRESS, &data, 4, 0); - return err >= 0 ? be32_to_cpu(data) : 0; -} - -static void fwspk_card_free(struct snd_card *card) -{ - struct fwspk *fwspk = card->private_data; - - amdtp_stream_destroy(&fwspk->stream); - cmp_connection_destroy(&fwspk->connection); - fw_unit_put(fwspk->unit); - mutex_destroy(&fwspk->mutex); -} - -static int fwspk_probe(struct fw_unit *unit, - const struct ieee1394_device_id *id) -{ - struct fw_device *fw_dev = fw_parent_device(unit); - struct snd_card *card; - struct fwspk *fwspk; - u32 firmware; - int err; - - err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, - sizeof(*fwspk), &card); - if (err < 0) - return err; - - fwspk = card->private_data; - fwspk->card = card; - mutex_init(&fwspk->mutex); - fwspk->unit = fw_unit_get(unit); - fwspk->device_info = (const struct device_info *)id->driver_data; - - err = cmp_connection_init(&fwspk->connection, unit, CMP_INPUT, 0); - if (err < 0) - goto err_unit; - - err = amdtp_stream_init(&fwspk->stream, unit, AMDTP_OUT_STREAM, - CIP_NONBLOCKING); - if (err < 0) - goto err_connection; - - card->private_free = fwspk_card_free; - - strcpy(card->driver, fwspk->device_info->driver_name); - strcpy(card->shortname, fwspk->device_info->short_name); - firmware = fwspk_read_firmware_version(unit); - snprintf(card->longname, sizeof(card->longname), - "%s (OXFW%x %04x), GUID %08x%08x at %s, S%d", - fwspk->device_info->long_name, - firmware >> 20, firmware & 0xffff, - fw_dev->config_rom[3], fw_dev->config_rom[4], - dev_name(&unit->device), 100 << fw_dev->max_speed); - strcpy(card->mixername, "OXFW970"); - - err = fwspk_create_pcm(fwspk); - if (err < 0) - goto error; - - err = fwspk_create_mixer(fwspk); - if (err < 0) - goto error; - - err = snd_card_register(card); - if (err < 0) - goto error; - - dev_set_drvdata(&unit->device, fwspk); - - return 0; - -err_connection: - cmp_connection_destroy(&fwspk->connection); -err_unit: - fw_unit_put(fwspk->unit); - mutex_destroy(&fwspk->mutex); -error: - snd_card_free(card); - return err; -} - -static void fwspk_bus_reset(struct fw_unit *unit) -{ - struct fwspk *fwspk = dev_get_drvdata(&unit->device); - - fcp_bus_reset(fwspk->unit); - - if (cmp_connection_update(&fwspk->connection) < 0) { - amdtp_stream_pcm_abort(&fwspk->stream); - mutex_lock(&fwspk->mutex); - fwspk_stop_stream(fwspk); - mutex_unlock(&fwspk->mutex); - return; - } - - amdtp_stream_update(&fwspk->stream); -} - -static void fwspk_remove(struct fw_unit *unit) -{ - struct fwspk *fwspk = dev_get_drvdata(&unit->device); - - amdtp_stream_pcm_abort(&fwspk->stream); - snd_card_disconnect(fwspk->card); - - mutex_lock(&fwspk->mutex); - fwspk_stop_stream(fwspk); - mutex_unlock(&fwspk->mutex); - - snd_card_free_when_closed(fwspk->card); -} - -static const struct device_info griffin_firewave = { - .driver_name = "FireWave", - .short_name = "FireWave", - .long_name = "Griffin FireWave Surround", - .pcm_constraints = firewave_constraints, - .mixer_channels = 6, - .mute_fb_id = 0x01, - .volume_fb_id = 0x02, -}; - -static const struct device_info lacie_speakers = { - .driver_name = "FWSpeakers", - .short_name = "FireWire Speakers", - .long_name = "LaCie FireWire Speakers", - .pcm_constraints = lacie_speakers_constraints, - .mixer_channels = 1, - .mute_fb_id = 0x01, - .volume_fb_id = 0x01, -}; - -static const struct ieee1394_device_id fwspk_id_table[] = { - { - .match_flags = IEEE1394_MATCH_VENDOR_ID | - IEEE1394_MATCH_MODEL_ID | - IEEE1394_MATCH_SPECIFIER_ID | - IEEE1394_MATCH_VERSION, - .vendor_id = VENDOR_GRIFFIN, - .model_id = 0x00f970, - .specifier_id = SPECIFIER_1394TA, - .version = VERSION_AVC, - .driver_data = (kernel_ulong_t)&griffin_firewave, - }, - { - .match_flags = IEEE1394_MATCH_VENDOR_ID | - IEEE1394_MATCH_MODEL_ID | - IEEE1394_MATCH_SPECIFIER_ID | - IEEE1394_MATCH_VERSION, - .vendor_id = VENDOR_LACIE, - .model_id = 0x00f970, - .specifier_id = SPECIFIER_1394TA, - .version = VERSION_AVC, - .driver_data = (kernel_ulong_t)&lacie_speakers, - }, - { } -}; -MODULE_DEVICE_TABLE(ieee1394, fwspk_id_table); - -static struct fw_driver fwspk_driver = { - .driver = { - .owner = THIS_MODULE, - .name = KBUILD_MODNAME, - .bus = &fw_bus_type, - }, - .probe = fwspk_probe, - .update = fwspk_bus_reset, - .remove = fwspk_remove, - .id_table = fwspk_id_table, -}; - -static int __init alsa_fwspk_init(void) -{ - return driver_register(&fwspk_driver.driver); -} - -static void __exit alsa_fwspk_exit(void) -{ - driver_unregister(&fwspk_driver.driver); -} - -module_init(alsa_fwspk_init); -module_exit(alsa_fwspk_exit); -- cgit v1.2.3 From 1a4e39c2e5ca2eb494a53ecd73055562f690bca0 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sat, 29 Nov 2014 00:59:26 +0900 Subject: ALSA: oxfw: Move to its own directory Followed commits add much codes. To make the work easy, this commit creates own directory and move current file to it. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/Makefile | 2 +- sound/firewire/oxfw.c | 793 ------------------------------------------- sound/firewire/oxfw/Makefile | 2 + sound/firewire/oxfw/oxfw.c | 793 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 796 insertions(+), 794 deletions(-) delete mode 100644 sound/firewire/oxfw.c create mode 100644 sound/firewire/oxfw/Makefile create mode 100644 sound/firewire/oxfw/oxfw.c (limited to 'sound') diff --git a/sound/firewire/Makefile b/sound/firewire/Makefile index 5ed6fb7bc979..8b37f084b2ab 100644 --- a/sound/firewire/Makefile +++ b/sound/firewire/Makefile @@ -6,7 +6,7 @@ snd-scs1x-objs := scs1x.o obj-$(CONFIG_SND_FIREWIRE_LIB) += snd-firewire-lib.o obj-$(CONFIG_SND_DICE) += dice/ -obj-$(CONFIG_SND_OXFW) += snd-oxfw.o +obj-$(CONFIG_SND_OXFW) += oxfw/ obj-$(CONFIG_SND_ISIGHT) += snd-isight.o obj-$(CONFIG_SND_SCS1X) += snd-scs1x.o obj-$(CONFIG_SND_FIREWORKS) += fireworks/ diff --git a/sound/firewire/oxfw.c b/sound/firewire/oxfw.c deleted file mode 100644 index b7498e9420d8..000000000000 --- a/sound/firewire/oxfw.c +++ /dev/null @@ -1,793 +0,0 @@ -/* - * oxfw.c - a part of driver for OXFW970/971 based devices - * - * Copyright (c) Clemens Ladisch - * Licensed under the terms of the GNU General Public License, version 2. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "cmp.h" -#include "fcp.h" -#include "amdtp.h" -#include "lib.h" - -#define OXFORD_FIRMWARE_ID_ADDRESS (CSR_REGISTER_BASE + 0x50000) -/* 0x970?vvvv or 0x971?vvvv, where vvvv = firmware version */ - -#define OXFORD_HARDWARE_ID_ADDRESS (CSR_REGISTER_BASE + 0x90020) -#define OXFORD_HARDWARE_ID_OXFW970 0x39443841 -#define OXFORD_HARDWARE_ID_OXFW971 0x39373100 - -#define VENDOR_GRIFFIN 0x001292 -#define VENDOR_LACIE 0x00d04b - -#define SPECIFIER_1394TA 0x00a02d -#define VERSION_AVC 0x010001 - -struct device_info { - const char *driver_name; - const char *short_name; - const char *long_name; - int (*pcm_constraints)(struct snd_pcm_runtime *runtime); - unsigned int mixer_channels; - u8 mute_fb_id; - u8 volume_fb_id; -}; - -struct snd_oxfw { - struct snd_card *card; - struct fw_unit *unit; - const struct device_info *device_info; - struct mutex mutex; - struct cmp_connection in_conn; - struct amdtp_stream rx_stream; - bool mute; - s16 volume[6]; - s16 volume_min; - s16 volume_max; -}; - -MODULE_DESCRIPTION("Oxford Semiconductor FW970/971 driver"); -MODULE_AUTHOR("Clemens Ladisch "); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("snd-firewire-speakers"); - -static int firewave_rate_constraint(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - static unsigned int stereo_rates[] = { 48000, 96000 }; - struct snd_interval *channels = - hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_interval *rate = - hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); - - /* two channels work only at 48/96 kHz */ - if (snd_interval_max(channels) < 6) - return snd_interval_list(rate, 2, stereo_rates, 0); - return 0; -} - -static int firewave_channels_constraint(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - static const struct snd_interval all_channels = { .min = 6, .max = 6 }; - struct snd_interval *rate = - hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *channels = - hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - - /* 32/44.1 kHz work only with all six channels */ - if (snd_interval_max(rate) < 48000) - return snd_interval_refine(channels, &all_channels); - return 0; -} - -static int firewave_constraints(struct snd_pcm_runtime *runtime) -{ - static unsigned int channels_list[] = { 2, 6 }; - static struct snd_pcm_hw_constraint_list channels_list_constraint = { - .count = 2, - .list = channels_list, - }; - int err; - - runtime->hw.rates = SNDRV_PCM_RATE_32000 | - SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_96000; - runtime->hw.channels_max = 6; - - err = snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, - &channels_list_constraint); - if (err < 0) - return err; - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - firewave_rate_constraint, NULL, - SNDRV_PCM_HW_PARAM_CHANNELS, -1); - if (err < 0) - return err; - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - firewave_channels_constraint, NULL, - SNDRV_PCM_HW_PARAM_RATE, -1); - if (err < 0) - return err; - - return 0; -} - -static int lacie_speakers_constraints(struct snd_pcm_runtime *runtime) -{ - runtime->hw.rates = SNDRV_PCM_RATE_32000 | - SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_88200 | - SNDRV_PCM_RATE_96000; - - return 0; -} - -static int oxfw_open(struct snd_pcm_substream *substream) -{ - static const struct snd_pcm_hardware hardware = { - .info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_BATCH | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER, - .formats = AMDTP_OUT_PCM_FORMAT_BITS, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = 4 * 1024 * 1024, - .period_bytes_min = 1, - .period_bytes_max = UINT_MAX, - .periods_min = 1, - .periods_max = UINT_MAX, - }; - struct snd_oxfw *oxfw = substream->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; - int err; - - runtime->hw = hardware; - - err = oxfw->device_info->pcm_constraints(runtime); - if (err < 0) - return err; - err = snd_pcm_limit_hw_rates(runtime); - if (err < 0) - return err; - - err = amdtp_stream_add_pcm_hw_constraints(&oxfw->rx_stream, runtime); - if (err < 0) - return err; - - return 0; -} - -static int oxfw_close(struct snd_pcm_substream *substream) -{ - return 0; -} - -static void oxfw_stop_stream(struct snd_oxfw *oxfw) -{ - if (amdtp_stream_running(&oxfw->rx_stream)) { - amdtp_stream_stop(&oxfw->rx_stream); - cmp_connection_break(&oxfw->in_conn); - } -} - -static int oxfw_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct snd_oxfw *oxfw = substream->private_data; - int err; - - mutex_lock(&oxfw->mutex); - oxfw_stop_stream(oxfw); - mutex_unlock(&oxfw->mutex); - - err = snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); - if (err < 0) - goto error; - - amdtp_stream_set_parameters(&oxfw->rx_stream, - params_rate(hw_params), - params_channels(hw_params), - 0); - - amdtp_stream_set_pcm_format(&oxfw->rx_stream, - params_format(hw_params)); - - err = avc_general_set_sig_fmt(oxfw->unit, params_rate(hw_params), - AVC_GENERAL_PLUG_DIR_IN, 0); - if (err < 0) { - dev_err(&oxfw->unit->device, "failed to set sample rate\n"); - goto err_buffer; - } - - return 0; - -err_buffer: - snd_pcm_lib_free_vmalloc_buffer(substream); -error: - return err; -} - -static int oxfw_hw_free(struct snd_pcm_substream *substream) -{ - struct snd_oxfw *oxfw = substream->private_data; - - mutex_lock(&oxfw->mutex); - oxfw_stop_stream(oxfw); - mutex_unlock(&oxfw->mutex); - - return snd_pcm_lib_free_vmalloc_buffer(substream); -} - -static int oxfw_prepare(struct snd_pcm_substream *substream) -{ - struct snd_oxfw *oxfw = substream->private_data; - int err; - - mutex_lock(&oxfw->mutex); - - if (amdtp_streaming_error(&oxfw->rx_stream)) - oxfw_stop_stream(oxfw); - - if (!amdtp_stream_running(&oxfw->rx_stream)) { - err = cmp_connection_establish(&oxfw->in_conn, - amdtp_stream_get_max_payload(&oxfw->rx_stream)); - if (err < 0) - goto err_mutex; - - err = amdtp_stream_start(&oxfw->rx_stream, - oxfw->in_conn.resources.channel, - oxfw->in_conn.speed); - if (err < 0) - goto err_connection; - } - - mutex_unlock(&oxfw->mutex); - - amdtp_stream_pcm_prepare(&oxfw->rx_stream); - - return 0; - -err_connection: - cmp_connection_break(&oxfw->in_conn); -err_mutex: - mutex_unlock(&oxfw->mutex); - - return err; -} - -static int oxfw_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct snd_oxfw *oxfw = substream->private_data; - struct snd_pcm_substream *pcm; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - pcm = substream; - break; - case SNDRV_PCM_TRIGGER_STOP: - pcm = NULL; - break; - default: - return -EINVAL; - } - amdtp_stream_pcm_trigger(&oxfw->rx_stream, pcm); - return 0; -} - -static snd_pcm_uframes_t oxfw_pointer(struct snd_pcm_substream *substream) -{ - struct snd_oxfw *oxfw = substream->private_data; - - return amdtp_stream_pcm_pointer(&oxfw->rx_stream); -} - -static int oxfw_create_pcm(struct snd_oxfw *oxfw) -{ - static struct snd_pcm_ops ops = { - .open = oxfw_open, - .close = oxfw_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = oxfw_hw_params, - .hw_free = oxfw_hw_free, - .prepare = oxfw_prepare, - .trigger = oxfw_trigger, - .pointer = oxfw_pointer, - .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, - }; - struct snd_pcm *pcm; - int err; - - err = snd_pcm_new(oxfw->card, "OXFW", 0, 1, 0, &pcm); - if (err < 0) - return err; - pcm->private_data = oxfw; - strcpy(pcm->name, oxfw->device_info->short_name); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ops); - return 0; -} - -enum control_action { CTL_READ, CTL_WRITE }; -enum control_attribute { - CTL_MIN = 0x02, - CTL_MAX = 0x03, - CTL_CURRENT = 0x10, -}; - -static int oxfw_mute_command(struct snd_oxfw *oxfw, bool *value, - enum control_action action) -{ - u8 *buf; - u8 response_ok; - int err; - - buf = kmalloc(11, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - if (action == CTL_READ) { - buf[0] = 0x01; /* AV/C, STATUS */ - response_ok = 0x0c; /* STABLE */ - } else { - buf[0] = 0x00; /* AV/C, CONTROL */ - response_ok = 0x09; /* ACCEPTED */ - } - buf[1] = 0x08; /* audio unit 0 */ - buf[2] = 0xb8; /* FUNCTION BLOCK */ - buf[3] = 0x81; /* function block type: feature */ - buf[4] = oxfw->device_info->mute_fb_id; /* function block ID */ - buf[5] = 0x10; /* control attribute: current */ - buf[6] = 0x02; /* selector length */ - buf[7] = 0x00; /* audio channel number */ - buf[8] = 0x01; /* control selector: mute */ - buf[9] = 0x01; /* control data length */ - if (action == CTL_READ) - buf[10] = 0xff; - else - buf[10] = *value ? 0x70 : 0x60; - - err = fcp_avc_transaction(oxfw->unit, buf, 11, buf, 11, 0x3fe); - if (err < 0) - goto error; - if (err < 11) { - dev_err(&oxfw->unit->device, "short FCP response\n"); - err = -EIO; - goto error; - } - if (buf[0] != response_ok) { - dev_err(&oxfw->unit->device, "mute command failed\n"); - err = -EIO; - goto error; - } - if (action == CTL_READ) - *value = buf[10] == 0x70; - - err = 0; - -error: - kfree(buf); - - return err; -} - -static int oxfw_volume_command(struct snd_oxfw *oxfw, s16 *value, - unsigned int channel, - enum control_attribute attribute, - enum control_action action) -{ - u8 *buf; - u8 response_ok; - int err; - - buf = kmalloc(12, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - if (action == CTL_READ) { - buf[0] = 0x01; /* AV/C, STATUS */ - response_ok = 0x0c; /* STABLE */ - } else { - buf[0] = 0x00; /* AV/C, CONTROL */ - response_ok = 0x09; /* ACCEPTED */ - } - buf[1] = 0x08; /* audio unit 0 */ - buf[2] = 0xb8; /* FUNCTION BLOCK */ - buf[3] = 0x81; /* function block type: feature */ - buf[4] = oxfw->device_info->volume_fb_id; /* function block ID */ - buf[5] = attribute; /* control attribute */ - buf[6] = 0x02; /* selector length */ - buf[7] = channel; /* audio channel number */ - buf[8] = 0x02; /* control selector: volume */ - buf[9] = 0x02; /* control data length */ - if (action == CTL_READ) { - buf[10] = 0xff; - buf[11] = 0xff; - } else { - buf[10] = *value >> 8; - buf[11] = *value; - } - - err = fcp_avc_transaction(oxfw->unit, buf, 12, buf, 12, 0x3fe); - if (err < 0) - goto error; - if (err < 12) { - dev_err(&oxfw->unit->device, "short FCP response\n"); - err = -EIO; - goto error; - } - if (buf[0] != response_ok) { - dev_err(&oxfw->unit->device, "volume command failed\n"); - err = -EIO; - goto error; - } - if (action == CTL_READ) - *value = (buf[10] << 8) | buf[11]; - - err = 0; - -error: - kfree(buf); - - return err; -} - -static int oxfw_mute_get(struct snd_kcontrol *control, - struct snd_ctl_elem_value *value) -{ - struct snd_oxfw *oxfw = control->private_data; - - value->value.integer.value[0] = !oxfw->mute; - - return 0; -} - -static int oxfw_mute_put(struct snd_kcontrol *control, - struct snd_ctl_elem_value *value) -{ - struct snd_oxfw *oxfw = control->private_data; - bool mute; - int err; - - mute = !value->value.integer.value[0]; - - if (mute == oxfw->mute) - return 0; - - err = oxfw_mute_command(oxfw, &mute, CTL_WRITE); - if (err < 0) - return err; - oxfw->mute = mute; - - return 1; -} - -static int oxfw_volume_info(struct snd_kcontrol *control, - struct snd_ctl_elem_info *info) -{ - struct snd_oxfw *oxfw = control->private_data; - - info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - info->count = oxfw->device_info->mixer_channels; - info->value.integer.min = oxfw->volume_min; - info->value.integer.max = oxfw->volume_max; - - return 0; -} - -static const u8 channel_map[6] = { 0, 1, 4, 5, 2, 3 }; - -static int oxfw_volume_get(struct snd_kcontrol *control, - struct snd_ctl_elem_value *value) -{ - struct snd_oxfw *oxfw = control->private_data; - unsigned int i; - - for (i = 0; i < oxfw->device_info->mixer_channels; ++i) - value->value.integer.value[channel_map[i]] = oxfw->volume[i]; - - return 0; -} - -static int oxfw_volume_put(struct snd_kcontrol *control, - struct snd_ctl_elem_value *value) -{ - struct snd_oxfw *oxfw = control->private_data; - unsigned int i, changed_channels; - bool equal_values = true; - s16 volume; - int err; - - for (i = 0; i < oxfw->device_info->mixer_channels; ++i) { - if (value->value.integer.value[i] < oxfw->volume_min || - value->value.integer.value[i] > oxfw->volume_max) - return -EINVAL; - if (value->value.integer.value[i] != - value->value.integer.value[0]) - equal_values = false; - } - - changed_channels = 0; - for (i = 0; i < oxfw->device_info->mixer_channels; ++i) - if (value->value.integer.value[channel_map[i]] != - oxfw->volume[i]) - changed_channels |= 1 << (i + 1); - - if (equal_values && changed_channels != 0) - changed_channels = 1 << 0; - - for (i = 0; i <= oxfw->device_info->mixer_channels; ++i) { - volume = value->value.integer.value[channel_map[i ? i - 1 : 0]]; - if (changed_channels & (1 << i)) { - err = oxfw_volume_command(oxfw, &volume, i, - CTL_CURRENT, CTL_WRITE); - if (err < 0) - return err; - } - if (i > 0) - oxfw->volume[i - 1] = volume; - } - - return changed_channels != 0; -} - -static int oxfw_create_mixer(struct snd_oxfw *oxfw) -{ - static const struct snd_kcontrol_new controls[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Playback Switch", - .info = snd_ctl_boolean_mono_info, - .get = oxfw_mute_get, - .put = oxfw_mute_put, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Playback Volume", - .info = oxfw_volume_info, - .get = oxfw_volume_get, - .put = oxfw_volume_put, - }, - }; - unsigned int i, first_ch; - int err; - - err = oxfw_volume_command(oxfw, &oxfw->volume_min, - 0, CTL_MIN, CTL_READ); - if (err < 0) - return err; - err = oxfw_volume_command(oxfw, &oxfw->volume_max, - 0, CTL_MAX, CTL_READ); - if (err < 0) - return err; - - err = oxfw_mute_command(oxfw, &oxfw->mute, CTL_READ); - if (err < 0) - return err; - - first_ch = oxfw->device_info->mixer_channels == 1 ? 0 : 1; - for (i = 0; i < oxfw->device_info->mixer_channels; ++i) { - err = oxfw_volume_command(oxfw, &oxfw->volume[i], - first_ch + i, CTL_CURRENT, CTL_READ); - if (err < 0) - return err; - } - - for (i = 0; i < ARRAY_SIZE(controls); ++i) { - err = snd_ctl_add(oxfw->card, - snd_ctl_new1(&controls[i], oxfw)); - if (err < 0) - return err; - } - - return 0; -} - -static u32 oxfw_read_firmware_version(struct fw_unit *unit) -{ - __be32 data; - int err; - - err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST, - OXFORD_FIRMWARE_ID_ADDRESS, &data, 4, 0); - return err >= 0 ? be32_to_cpu(data) : 0; -} - -static void oxfw_card_free(struct snd_card *card) -{ - struct snd_oxfw *oxfw = card->private_data; - - amdtp_stream_destroy(&oxfw->rx_stream); - cmp_connection_destroy(&oxfw->in_conn); - fw_unit_put(oxfw->unit); - mutex_destroy(&oxfw->mutex); -} - -static int oxfw_probe(struct fw_unit *unit, - const struct ieee1394_device_id *id) -{ - struct fw_device *fw_dev = fw_parent_device(unit); - struct snd_card *card; - struct snd_oxfw *oxfw; - u32 firmware; - int err; - - err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, - sizeof(*oxfw), &card); - if (err < 0) - return err; - - oxfw = card->private_data; - oxfw->card = card; - mutex_init(&oxfw->mutex); - oxfw->unit = fw_unit_get(unit); - oxfw->device_info = (const struct device_info *)id->driver_data; - - err = cmp_connection_init(&oxfw->in_conn, unit, CMP_INPUT, 0); - if (err < 0) - goto err_unit; - - err = amdtp_stream_init(&oxfw->rx_stream, unit, AMDTP_OUT_STREAM, - CIP_NONBLOCKING); - if (err < 0) - goto err_connection; - - card->private_free = oxfw_card_free; - - strcpy(card->driver, oxfw->device_info->driver_name); - strcpy(card->shortname, oxfw->device_info->short_name); - firmware = oxfw_read_firmware_version(unit); - snprintf(card->longname, sizeof(card->longname), - "%s (OXFW%x %04x), GUID %08x%08x at %s, S%d", - oxfw->device_info->long_name, - firmware >> 20, firmware & 0xffff, - fw_dev->config_rom[3], fw_dev->config_rom[4], - dev_name(&unit->device), 100 << fw_dev->max_speed); - strcpy(card->mixername, "OXFW"); - - err = oxfw_create_pcm(oxfw); - if (err < 0) - goto error; - - err = oxfw_create_mixer(oxfw); - if (err < 0) - goto error; - - err = snd_card_register(card); - if (err < 0) - goto error; - - dev_set_drvdata(&unit->device, oxfw); - - return 0; - -err_connection: - cmp_connection_destroy(&oxfw->in_conn); -err_unit: - fw_unit_put(oxfw->unit); - mutex_destroy(&oxfw->mutex); -error: - snd_card_free(card); - return err; -} - -static void oxfw_bus_reset(struct fw_unit *unit) -{ - struct snd_oxfw *oxfw = dev_get_drvdata(&unit->device); - - fcp_bus_reset(oxfw->unit); - - if (cmp_connection_update(&oxfw->in_conn) < 0) { - amdtp_stream_pcm_abort(&oxfw->rx_stream); - mutex_lock(&oxfw->mutex); - oxfw_stop_stream(oxfw); - mutex_unlock(&oxfw->mutex); - return; - } - - amdtp_stream_update(&oxfw->rx_stream); -} - -static void oxfw_remove(struct fw_unit *unit) -{ - struct snd_oxfw *oxfw = dev_get_drvdata(&unit->device); - - amdtp_stream_pcm_abort(&oxfw->rx_stream); - snd_card_disconnect(oxfw->card); - - mutex_lock(&oxfw->mutex); - oxfw_stop_stream(oxfw); - mutex_unlock(&oxfw->mutex); - - snd_card_free_when_closed(oxfw->card); -} - -static const struct device_info griffin_firewave = { - .driver_name = "FireWave", - .short_name = "FireWave", - .long_name = "Griffin FireWave Surround", - .pcm_constraints = firewave_constraints, - .mixer_channels = 6, - .mute_fb_id = 0x01, - .volume_fb_id = 0x02, -}; - -static const struct device_info lacie_speakers = { - .driver_name = "FWSpeakers", - .short_name = "FireWire Speakers", - .long_name = "LaCie FireWire Speakers", - .pcm_constraints = lacie_speakers_constraints, - .mixer_channels = 1, - .mute_fb_id = 0x01, - .volume_fb_id = 0x01, -}; - -static const struct ieee1394_device_id oxfw_id_table[] = { - { - .match_flags = IEEE1394_MATCH_VENDOR_ID | - IEEE1394_MATCH_MODEL_ID | - IEEE1394_MATCH_SPECIFIER_ID | - IEEE1394_MATCH_VERSION, - .vendor_id = VENDOR_GRIFFIN, - .model_id = 0x00f970, - .specifier_id = SPECIFIER_1394TA, - .version = VERSION_AVC, - .driver_data = (kernel_ulong_t)&griffin_firewave, - }, - { - .match_flags = IEEE1394_MATCH_VENDOR_ID | - IEEE1394_MATCH_MODEL_ID | - IEEE1394_MATCH_SPECIFIER_ID | - IEEE1394_MATCH_VERSION, - .vendor_id = VENDOR_LACIE, - .model_id = 0x00f970, - .specifier_id = SPECIFIER_1394TA, - .version = VERSION_AVC, - .driver_data = (kernel_ulong_t)&lacie_speakers, - }, - { } -}; -MODULE_DEVICE_TABLE(ieee1394, oxfw_id_table); - -static struct fw_driver oxfw_driver = { - .driver = { - .owner = THIS_MODULE, - .name = KBUILD_MODNAME, - .bus = &fw_bus_type, - }, - .probe = oxfw_probe, - .update = oxfw_bus_reset, - .remove = oxfw_remove, - .id_table = oxfw_id_table, -}; - -static int __init snd_oxfw_init(void) -{ - return driver_register(&oxfw_driver.driver); -} - -static void __exit snd_oxfw_exit(void) -{ - driver_unregister(&oxfw_driver.driver); -} - -module_init(snd_oxfw_init); -module_exit(snd_oxfw_exit); diff --git a/sound/firewire/oxfw/Makefile b/sound/firewire/oxfw/Makefile new file mode 100644 index 000000000000..9ca49c0fdc40 --- /dev/null +++ b/sound/firewire/oxfw/Makefile @@ -0,0 +1,2 @@ +snd-oxfw-objs := oxfw.o +obj-m += snd-oxfw.o diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c new file mode 100644 index 000000000000..55c687ef3247 --- /dev/null +++ b/sound/firewire/oxfw/oxfw.c @@ -0,0 +1,793 @@ +/* + * oxfw.c - a part of driver for OXFW970/971 based devices + * + * Copyright (c) Clemens Ladisch + * Licensed under the terms of the GNU General Public License, version 2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../cmp.h" +#include "../fcp.h" +#include "../amdtp.h" +#include "../lib.h" + +#define OXFORD_FIRMWARE_ID_ADDRESS (CSR_REGISTER_BASE + 0x50000) +/* 0x970?vvvv or 0x971?vvvv, where vvvv = firmware version */ + +#define OXFORD_HARDWARE_ID_ADDRESS (CSR_REGISTER_BASE + 0x90020) +#define OXFORD_HARDWARE_ID_OXFW970 0x39443841 +#define OXFORD_HARDWARE_ID_OXFW971 0x39373100 + +#define VENDOR_GRIFFIN 0x001292 +#define VENDOR_LACIE 0x00d04b + +#define SPECIFIER_1394TA 0x00a02d +#define VERSION_AVC 0x010001 + +struct device_info { + const char *driver_name; + const char *short_name; + const char *long_name; + int (*pcm_constraints)(struct snd_pcm_runtime *runtime); + unsigned int mixer_channels; + u8 mute_fb_id; + u8 volume_fb_id; +}; + +struct snd_oxfw { + struct snd_card *card; + struct fw_unit *unit; + const struct device_info *device_info; + struct mutex mutex; + struct cmp_connection in_conn; + struct amdtp_stream rx_stream; + bool mute; + s16 volume[6]; + s16 volume_min; + s16 volume_max; +}; + +MODULE_DESCRIPTION("Oxford Semiconductor FW970/971 driver"); +MODULE_AUTHOR("Clemens Ladisch "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("snd-firewire-speakers"); + +static int firewave_rate_constraint(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + static unsigned int stereo_rates[] = { 48000, 96000 }; + struct snd_interval *channels = + hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_interval *rate = + hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + + /* two channels work only at 48/96 kHz */ + if (snd_interval_max(channels) < 6) + return snd_interval_list(rate, 2, stereo_rates, 0); + return 0; +} + +static int firewave_channels_constraint(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + static const struct snd_interval all_channels = { .min = 6, .max = 6 }; + struct snd_interval *rate = + hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = + hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + + /* 32/44.1 kHz work only with all six channels */ + if (snd_interval_max(rate) < 48000) + return snd_interval_refine(channels, &all_channels); + return 0; +} + +static int firewave_constraints(struct snd_pcm_runtime *runtime) +{ + static unsigned int channels_list[] = { 2, 6 }; + static struct snd_pcm_hw_constraint_list channels_list_constraint = { + .count = 2, + .list = channels_list, + }; + int err; + + runtime->hw.rates = SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_96000; + runtime->hw.channels_max = 6; + + err = snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, + &channels_list_constraint); + if (err < 0) + return err; + err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + firewave_rate_constraint, NULL, + SNDRV_PCM_HW_PARAM_CHANNELS, -1); + if (err < 0) + return err; + err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + firewave_channels_constraint, NULL, + SNDRV_PCM_HW_PARAM_RATE, -1); + if (err < 0) + return err; + + return 0; +} + +static int lacie_speakers_constraints(struct snd_pcm_runtime *runtime) +{ + runtime->hw.rates = SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000; + + return 0; +} + +static int oxfw_open(struct snd_pcm_substream *substream) +{ + static const struct snd_pcm_hardware hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_BATCH | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER, + .formats = AMDTP_OUT_PCM_FORMAT_BITS, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 4 * 1024 * 1024, + .period_bytes_min = 1, + .period_bytes_max = UINT_MAX, + .periods_min = 1, + .periods_max = UINT_MAX, + }; + struct snd_oxfw *oxfw = substream->private_data; + struct snd_pcm_runtime *runtime = substream->runtime; + int err; + + runtime->hw = hardware; + + err = oxfw->device_info->pcm_constraints(runtime); + if (err < 0) + return err; + err = snd_pcm_limit_hw_rates(runtime); + if (err < 0) + return err; + + err = amdtp_stream_add_pcm_hw_constraints(&oxfw->rx_stream, runtime); + if (err < 0) + return err; + + return 0; +} + +static int oxfw_close(struct snd_pcm_substream *substream) +{ + return 0; +} + +static void oxfw_stop_stream(struct snd_oxfw *oxfw) +{ + if (amdtp_stream_running(&oxfw->rx_stream)) { + amdtp_stream_stop(&oxfw->rx_stream); + cmp_connection_break(&oxfw->in_conn); + } +} + +static int oxfw_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct snd_oxfw *oxfw = substream->private_data; + int err; + + mutex_lock(&oxfw->mutex); + oxfw_stop_stream(oxfw); + mutex_unlock(&oxfw->mutex); + + err = snd_pcm_lib_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); + if (err < 0) + goto error; + + amdtp_stream_set_parameters(&oxfw->rx_stream, + params_rate(hw_params), + params_channels(hw_params), + 0); + + amdtp_stream_set_pcm_format(&oxfw->rx_stream, + params_format(hw_params)); + + err = avc_general_set_sig_fmt(oxfw->unit, params_rate(hw_params), + AVC_GENERAL_PLUG_DIR_IN, 0); + if (err < 0) { + dev_err(&oxfw->unit->device, "failed to set sample rate\n"); + goto err_buffer; + } + + return 0; + +err_buffer: + snd_pcm_lib_free_vmalloc_buffer(substream); +error: + return err; +} + +static int oxfw_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_oxfw *oxfw = substream->private_data; + + mutex_lock(&oxfw->mutex); + oxfw_stop_stream(oxfw); + mutex_unlock(&oxfw->mutex); + + return snd_pcm_lib_free_vmalloc_buffer(substream); +} + +static int oxfw_prepare(struct snd_pcm_substream *substream) +{ + struct snd_oxfw *oxfw = substream->private_data; + int err; + + mutex_lock(&oxfw->mutex); + + if (amdtp_streaming_error(&oxfw->rx_stream)) + oxfw_stop_stream(oxfw); + + if (!amdtp_stream_running(&oxfw->rx_stream)) { + err = cmp_connection_establish(&oxfw->in_conn, + amdtp_stream_get_max_payload(&oxfw->rx_stream)); + if (err < 0) + goto err_mutex; + + err = amdtp_stream_start(&oxfw->rx_stream, + oxfw->in_conn.resources.channel, + oxfw->in_conn.speed); + if (err < 0) + goto err_connection; + } + + mutex_unlock(&oxfw->mutex); + + amdtp_stream_pcm_prepare(&oxfw->rx_stream); + + return 0; + +err_connection: + cmp_connection_break(&oxfw->in_conn); +err_mutex: + mutex_unlock(&oxfw->mutex); + + return err; +} + +static int oxfw_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_oxfw *oxfw = substream->private_data; + struct snd_pcm_substream *pcm; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + pcm = substream; + break; + case SNDRV_PCM_TRIGGER_STOP: + pcm = NULL; + break; + default: + return -EINVAL; + } + amdtp_stream_pcm_trigger(&oxfw->rx_stream, pcm); + return 0; +} + +static snd_pcm_uframes_t oxfw_pointer(struct snd_pcm_substream *substream) +{ + struct snd_oxfw *oxfw = substream->private_data; + + return amdtp_stream_pcm_pointer(&oxfw->rx_stream); +} + +static int oxfw_create_pcm(struct snd_oxfw *oxfw) +{ + static struct snd_pcm_ops ops = { + .open = oxfw_open, + .close = oxfw_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = oxfw_hw_params, + .hw_free = oxfw_hw_free, + .prepare = oxfw_prepare, + .trigger = oxfw_trigger, + .pointer = oxfw_pointer, + .page = snd_pcm_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, + }; + struct snd_pcm *pcm; + int err; + + err = snd_pcm_new(oxfw->card, "OXFW", 0, 1, 0, &pcm); + if (err < 0) + return err; + pcm->private_data = oxfw; + strcpy(pcm->name, oxfw->device_info->short_name); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ops); + return 0; +} + +enum control_action { CTL_READ, CTL_WRITE }; +enum control_attribute { + CTL_MIN = 0x02, + CTL_MAX = 0x03, + CTL_CURRENT = 0x10, +}; + +static int oxfw_mute_command(struct snd_oxfw *oxfw, bool *value, + enum control_action action) +{ + u8 *buf; + u8 response_ok; + int err; + + buf = kmalloc(11, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (action == CTL_READ) { + buf[0] = 0x01; /* AV/C, STATUS */ + response_ok = 0x0c; /* STABLE */ + } else { + buf[0] = 0x00; /* AV/C, CONTROL */ + response_ok = 0x09; /* ACCEPTED */ + } + buf[1] = 0x08; /* audio unit 0 */ + buf[2] = 0xb8; /* FUNCTION BLOCK */ + buf[3] = 0x81; /* function block type: feature */ + buf[4] = oxfw->device_info->mute_fb_id; /* function block ID */ + buf[5] = 0x10; /* control attribute: current */ + buf[6] = 0x02; /* selector length */ + buf[7] = 0x00; /* audio channel number */ + buf[8] = 0x01; /* control selector: mute */ + buf[9] = 0x01; /* control data length */ + if (action == CTL_READ) + buf[10] = 0xff; + else + buf[10] = *value ? 0x70 : 0x60; + + err = fcp_avc_transaction(oxfw->unit, buf, 11, buf, 11, 0x3fe); + if (err < 0) + goto error; + if (err < 11) { + dev_err(&oxfw->unit->device, "short FCP response\n"); + err = -EIO; + goto error; + } + if (buf[0] != response_ok) { + dev_err(&oxfw->unit->device, "mute command failed\n"); + err = -EIO; + goto error; + } + if (action == CTL_READ) + *value = buf[10] == 0x70; + + err = 0; + +error: + kfree(buf); + + return err; +} + +static int oxfw_volume_command(struct snd_oxfw *oxfw, s16 *value, + unsigned int channel, + enum control_attribute attribute, + enum control_action action) +{ + u8 *buf; + u8 response_ok; + int err; + + buf = kmalloc(12, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (action == CTL_READ) { + buf[0] = 0x01; /* AV/C, STATUS */ + response_ok = 0x0c; /* STABLE */ + } else { + buf[0] = 0x00; /* AV/C, CONTROL */ + response_ok = 0x09; /* ACCEPTED */ + } + buf[1] = 0x08; /* audio unit 0 */ + buf[2] = 0xb8; /* FUNCTION BLOCK */ + buf[3] = 0x81; /* function block type: feature */ + buf[4] = oxfw->device_info->volume_fb_id; /* function block ID */ + buf[5] = attribute; /* control attribute */ + buf[6] = 0x02; /* selector length */ + buf[7] = channel; /* audio channel number */ + buf[8] = 0x02; /* control selector: volume */ + buf[9] = 0x02; /* control data length */ + if (action == CTL_READ) { + buf[10] = 0xff; + buf[11] = 0xff; + } else { + buf[10] = *value >> 8; + buf[11] = *value; + } + + err = fcp_avc_transaction(oxfw->unit, buf, 12, buf, 12, 0x3fe); + if (err < 0) + goto error; + if (err < 12) { + dev_err(&oxfw->unit->device, "short FCP response\n"); + err = -EIO; + goto error; + } + if (buf[0] != response_ok) { + dev_err(&oxfw->unit->device, "volume command failed\n"); + err = -EIO; + goto error; + } + if (action == CTL_READ) + *value = (buf[10] << 8) | buf[11]; + + err = 0; + +error: + kfree(buf); + + return err; +} + +static int oxfw_mute_get(struct snd_kcontrol *control, + struct snd_ctl_elem_value *value) +{ + struct snd_oxfw *oxfw = control->private_data; + + value->value.integer.value[0] = !oxfw->mute; + + return 0; +} + +static int oxfw_mute_put(struct snd_kcontrol *control, + struct snd_ctl_elem_value *value) +{ + struct snd_oxfw *oxfw = control->private_data; + bool mute; + int err; + + mute = !value->value.integer.value[0]; + + if (mute == oxfw->mute) + return 0; + + err = oxfw_mute_command(oxfw, &mute, CTL_WRITE); + if (err < 0) + return err; + oxfw->mute = mute; + + return 1; +} + +static int oxfw_volume_info(struct snd_kcontrol *control, + struct snd_ctl_elem_info *info) +{ + struct snd_oxfw *oxfw = control->private_data; + + info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + info->count = oxfw->device_info->mixer_channels; + info->value.integer.min = oxfw->volume_min; + info->value.integer.max = oxfw->volume_max; + + return 0; +} + +static const u8 channel_map[6] = { 0, 1, 4, 5, 2, 3 }; + +static int oxfw_volume_get(struct snd_kcontrol *control, + struct snd_ctl_elem_value *value) +{ + struct snd_oxfw *oxfw = control->private_data; + unsigned int i; + + for (i = 0; i < oxfw->device_info->mixer_channels; ++i) + value->value.integer.value[channel_map[i]] = oxfw->volume[i]; + + return 0; +} + +static int oxfw_volume_put(struct snd_kcontrol *control, + struct snd_ctl_elem_value *value) +{ + struct snd_oxfw *oxfw = control->private_data; + unsigned int i, changed_channels; + bool equal_values = true; + s16 volume; + int err; + + for (i = 0; i < oxfw->device_info->mixer_channels; ++i) { + if (value->value.integer.value[i] < oxfw->volume_min || + value->value.integer.value[i] > oxfw->volume_max) + return -EINVAL; + if (value->value.integer.value[i] != + value->value.integer.value[0]) + equal_values = false; + } + + changed_channels = 0; + for (i = 0; i < oxfw->device_info->mixer_channels; ++i) + if (value->value.integer.value[channel_map[i]] != + oxfw->volume[i]) + changed_channels |= 1 << (i + 1); + + if (equal_values && changed_channels != 0) + changed_channels = 1 << 0; + + for (i = 0; i <= oxfw->device_info->mixer_channels; ++i) { + volume = value->value.integer.value[channel_map[i ? i - 1 : 0]]; + if (changed_channels & (1 << i)) { + err = oxfw_volume_command(oxfw, &volume, i, + CTL_CURRENT, CTL_WRITE); + if (err < 0) + return err; + } + if (i > 0) + oxfw->volume[i - 1] = volume; + } + + return changed_channels != 0; +} + +static int oxfw_create_mixer(struct snd_oxfw *oxfw) +{ + static const struct snd_kcontrol_new controls[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "PCM Playback Switch", + .info = snd_ctl_boolean_mono_info, + .get = oxfw_mute_get, + .put = oxfw_mute_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "PCM Playback Volume", + .info = oxfw_volume_info, + .get = oxfw_volume_get, + .put = oxfw_volume_put, + }, + }; + unsigned int i, first_ch; + int err; + + err = oxfw_volume_command(oxfw, &oxfw->volume_min, + 0, CTL_MIN, CTL_READ); + if (err < 0) + return err; + err = oxfw_volume_command(oxfw, &oxfw->volume_max, + 0, CTL_MAX, CTL_READ); + if (err < 0) + return err; + + err = oxfw_mute_command(oxfw, &oxfw->mute, CTL_READ); + if (err < 0) + return err; + + first_ch = oxfw->device_info->mixer_channels == 1 ? 0 : 1; + for (i = 0; i < oxfw->device_info->mixer_channels; ++i) { + err = oxfw_volume_command(oxfw, &oxfw->volume[i], + first_ch + i, CTL_CURRENT, CTL_READ); + if (err < 0) + return err; + } + + for (i = 0; i < ARRAY_SIZE(controls); ++i) { + err = snd_ctl_add(oxfw->card, + snd_ctl_new1(&controls[i], oxfw)); + if (err < 0) + return err; + } + + return 0; +} + +static u32 oxfw_read_firmware_version(struct fw_unit *unit) +{ + __be32 data; + int err; + + err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST, + OXFORD_FIRMWARE_ID_ADDRESS, &data, 4, 0); + return err >= 0 ? be32_to_cpu(data) : 0; +} + +static void oxfw_card_free(struct snd_card *card) +{ + struct snd_oxfw *oxfw = card->private_data; + + amdtp_stream_destroy(&oxfw->rx_stream); + cmp_connection_destroy(&oxfw->in_conn); + fw_unit_put(oxfw->unit); + mutex_destroy(&oxfw->mutex); +} + +static int oxfw_probe(struct fw_unit *unit, + const struct ieee1394_device_id *id) +{ + struct fw_device *fw_dev = fw_parent_device(unit); + struct snd_card *card; + struct snd_oxfw *oxfw; + u32 firmware; + int err; + + err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, + sizeof(*oxfw), &card); + if (err < 0) + return err; + + oxfw = card->private_data; + oxfw->card = card; + mutex_init(&oxfw->mutex); + oxfw->unit = fw_unit_get(unit); + oxfw->device_info = (const struct device_info *)id->driver_data; + + err = cmp_connection_init(&oxfw->in_conn, unit, CMP_INPUT, 0); + if (err < 0) + goto err_unit; + + err = amdtp_stream_init(&oxfw->rx_stream, unit, AMDTP_OUT_STREAM, + CIP_NONBLOCKING); + if (err < 0) + goto err_connection; + + card->private_free = oxfw_card_free; + + strcpy(card->driver, oxfw->device_info->driver_name); + strcpy(card->shortname, oxfw->device_info->short_name); + firmware = oxfw_read_firmware_version(unit); + snprintf(card->longname, sizeof(card->longname), + "%s (OXFW%x %04x), GUID %08x%08x at %s, S%d", + oxfw->device_info->long_name, + firmware >> 20, firmware & 0xffff, + fw_dev->config_rom[3], fw_dev->config_rom[4], + dev_name(&unit->device), 100 << fw_dev->max_speed); + strcpy(card->mixername, "OXFW"); + + err = oxfw_create_pcm(oxfw); + if (err < 0) + goto error; + + err = oxfw_create_mixer(oxfw); + if (err < 0) + goto error; + + err = snd_card_register(card); + if (err < 0) + goto error; + + dev_set_drvdata(&unit->device, oxfw); + + return 0; + +err_connection: + cmp_connection_destroy(&oxfw->in_conn); +err_unit: + fw_unit_put(oxfw->unit); + mutex_destroy(&oxfw->mutex); +error: + snd_card_free(card); + return err; +} + +static void oxfw_bus_reset(struct fw_unit *unit) +{ + struct snd_oxfw *oxfw = dev_get_drvdata(&unit->device); + + fcp_bus_reset(oxfw->unit); + + if (cmp_connection_update(&oxfw->in_conn) < 0) { + amdtp_stream_pcm_abort(&oxfw->rx_stream); + mutex_lock(&oxfw->mutex); + oxfw_stop_stream(oxfw); + mutex_unlock(&oxfw->mutex); + return; + } + + amdtp_stream_update(&oxfw->rx_stream); +} + +static void oxfw_remove(struct fw_unit *unit) +{ + struct snd_oxfw *oxfw = dev_get_drvdata(&unit->device); + + amdtp_stream_pcm_abort(&oxfw->rx_stream); + snd_card_disconnect(oxfw->card); + + mutex_lock(&oxfw->mutex); + oxfw_stop_stream(oxfw); + mutex_unlock(&oxfw->mutex); + + snd_card_free_when_closed(oxfw->card); +} + +static const struct device_info griffin_firewave = { + .driver_name = "FireWave", + .short_name = "FireWave", + .long_name = "Griffin FireWave Surround", + .pcm_constraints = firewave_constraints, + .mixer_channels = 6, + .mute_fb_id = 0x01, + .volume_fb_id = 0x02, +}; + +static const struct device_info lacie_speakers = { + .driver_name = "FWSpeakers", + .short_name = "FireWire Speakers", + .long_name = "LaCie FireWire Speakers", + .pcm_constraints = lacie_speakers_constraints, + .mixer_channels = 1, + .mute_fb_id = 0x01, + .volume_fb_id = 0x01, +}; + +static const struct ieee1394_device_id oxfw_id_table[] = { + { + .match_flags = IEEE1394_MATCH_VENDOR_ID | + IEEE1394_MATCH_MODEL_ID | + IEEE1394_MATCH_SPECIFIER_ID | + IEEE1394_MATCH_VERSION, + .vendor_id = VENDOR_GRIFFIN, + .model_id = 0x00f970, + .specifier_id = SPECIFIER_1394TA, + .version = VERSION_AVC, + .driver_data = (kernel_ulong_t)&griffin_firewave, + }, + { + .match_flags = IEEE1394_MATCH_VENDOR_ID | + IEEE1394_MATCH_MODEL_ID | + IEEE1394_MATCH_SPECIFIER_ID | + IEEE1394_MATCH_VERSION, + .vendor_id = VENDOR_LACIE, + .model_id = 0x00f970, + .specifier_id = SPECIFIER_1394TA, + .version = VERSION_AVC, + .driver_data = (kernel_ulong_t)&lacie_speakers, + }, + { } +}; +MODULE_DEVICE_TABLE(ieee1394, oxfw_id_table); + +static struct fw_driver oxfw_driver = { + .driver = { + .owner = THIS_MODULE, + .name = KBUILD_MODNAME, + .bus = &fw_bus_type, + }, + .probe = oxfw_probe, + .update = oxfw_bus_reset, + .remove = oxfw_remove, + .id_table = oxfw_id_table, +}; + +static int __init snd_oxfw_init(void) +{ + return driver_register(&oxfw_driver.driver); +} + +static void __exit snd_oxfw_exit(void) +{ + driver_unregister(&oxfw_driver.driver); +} + +module_init(snd_oxfw_init); +module_exit(snd_oxfw_exit); -- cgit v1.2.3 From e2786ca648d780d106bd8abca06746eb30d15ee7 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sat, 29 Nov 2014 00:59:27 +0900 Subject: ALSA: oxfw: Split stream functionality to a new file and add a header file This is a help for works in followed patches. And this commit remove 'fw_unit_get()/fw_unit_put()' because these are called by helper functions in 'snd-firewire-lib'. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/oxfw/Makefile | 2 +- sound/firewire/oxfw/oxfw-stream.c | 80 +++++++++++++++++++++++ sound/firewire/oxfw/oxfw.c | 130 +++++++------------------------------- sound/firewire/oxfw/oxfw.h | 56 ++++++++++++++++ 4 files changed, 159 insertions(+), 109 deletions(-) create mode 100644 sound/firewire/oxfw/oxfw-stream.c create mode 100644 sound/firewire/oxfw/oxfw.h (limited to 'sound') diff --git a/sound/firewire/oxfw/Makefile b/sound/firewire/oxfw/Makefile index 9ca49c0fdc40..e15c4c07b49d 100644 --- a/sound/firewire/oxfw/Makefile +++ b/sound/firewire/oxfw/Makefile @@ -1,2 +1,2 @@ -snd-oxfw-objs := oxfw.o +snd-oxfw-objs := oxfw-stream.o oxfw.o obj-m += snd-oxfw.o diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c new file mode 100644 index 000000000000..ebd156f3e29d --- /dev/null +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -0,0 +1,80 @@ +/* + * oxfw_stream.c - a part of driver for OXFW970/971 based devices + * + * Copyright (c) 2014 Takashi Sakamoto + * + * Licensed under the terms of the GNU General Public License, version 2. + */ + +#include "oxfw.h" + +int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw) +{ + int err; + + err = cmp_connection_init(&oxfw->in_conn, oxfw->unit, + CMP_INPUT, 0); + if (err < 0) + goto end; + + err = amdtp_stream_init(&oxfw->rx_stream, oxfw->unit, + AMDTP_OUT_STREAM, CIP_NONBLOCKING); + if (err < 0) { + amdtp_stream_destroy(&oxfw->rx_stream); + cmp_connection_destroy(&oxfw->in_conn); + } +end: + return err; +} + +static void stop_stream(struct snd_oxfw *oxfw) +{ + amdtp_stream_pcm_abort(&oxfw->rx_stream); + amdtp_stream_stop(&oxfw->rx_stream); + cmp_connection_break(&oxfw->in_conn); +} + +int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw) +{ + int err = 0; + + if (amdtp_streaming_error(&oxfw->rx_stream)) + stop_stream(oxfw); + + if (amdtp_stream_running(&oxfw->rx_stream)) + goto end; + + err = cmp_connection_establish(&oxfw->in_conn, + amdtp_stream_get_max_payload(&oxfw->rx_stream)); + if (err < 0) + goto end; + + err = amdtp_stream_start(&oxfw->rx_stream, + oxfw->in_conn.resources.channel, + oxfw->in_conn.speed); + if (err < 0) + stop_stream(oxfw); +end: + return err; +} + +void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw) +{ + stop_stream(oxfw); +} + +void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw) +{ + stop_stream(oxfw); + + amdtp_stream_destroy(&oxfw->rx_stream); + cmp_connection_destroy(&oxfw->in_conn); +} + +void snd_oxfw_stream_update_simplex(struct snd_oxfw *oxfw) +{ + if (cmp_connection_update(&oxfw->in_conn) < 0) + stop_stream(oxfw); + else + amdtp_stream_update(&oxfw->rx_stream); +} diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 55c687ef3247..40556677ea07 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -5,22 +5,7 @@ * Licensed under the terms of the GNU General Public License, version 2. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../cmp.h" -#include "../fcp.h" -#include "../amdtp.h" -#include "../lib.h" +#include "oxfw.h" #define OXFORD_FIRMWARE_ID_ADDRESS (CSR_REGISTER_BASE + 0x50000) /* 0x970?vvvv or 0x971?vvvv, where vvvv = firmware version */ @@ -35,29 +20,6 @@ #define SPECIFIER_1394TA 0x00a02d #define VERSION_AVC 0x010001 -struct device_info { - const char *driver_name; - const char *short_name; - const char *long_name; - int (*pcm_constraints)(struct snd_pcm_runtime *runtime); - unsigned int mixer_channels; - u8 mute_fb_id; - u8 volume_fb_id; -}; - -struct snd_oxfw { - struct snd_card *card; - struct fw_unit *unit; - const struct device_info *device_info; - struct mutex mutex; - struct cmp_connection in_conn; - struct amdtp_stream rx_stream; - bool mute; - s16 volume[6]; - s16 volume_min; - s16 volume_max; -}; - MODULE_DESCRIPTION("Oxford Semiconductor FW970/971 driver"); MODULE_AUTHOR("Clemens Ladisch "); MODULE_LICENSE("GPL v2"); @@ -180,14 +142,6 @@ static int oxfw_close(struct snd_pcm_substream *substream) return 0; } -static void oxfw_stop_stream(struct snd_oxfw *oxfw) -{ - if (amdtp_stream_running(&oxfw->rx_stream)) { - amdtp_stream_stop(&oxfw->rx_stream); - cmp_connection_break(&oxfw->in_conn); - } -} - static int oxfw_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { @@ -195,8 +149,8 @@ static int oxfw_hw_params(struct snd_pcm_substream *substream, int err; mutex_lock(&oxfw->mutex); - oxfw_stop_stream(oxfw); - mutex_unlock(&oxfw->mutex); + + snd_oxfw_stream_stop_simplex(oxfw); err = snd_pcm_lib_alloc_vmalloc_buffer(substream, params_buffer_bytes(hw_params)); @@ -223,6 +177,7 @@ static int oxfw_hw_params(struct snd_pcm_substream *substream, err_buffer: snd_pcm_lib_free_vmalloc_buffer(substream); error: + mutex_unlock(&oxfw->mutex); return err; } @@ -231,7 +186,7 @@ static int oxfw_hw_free(struct snd_pcm_substream *substream) struct snd_oxfw *oxfw = substream->private_data; mutex_lock(&oxfw->mutex); - oxfw_stop_stream(oxfw); + snd_oxfw_stream_stop_simplex(oxfw); mutex_unlock(&oxfw->mutex); return snd_pcm_lib_free_vmalloc_buffer(substream); @@ -244,33 +199,15 @@ static int oxfw_prepare(struct snd_pcm_substream *substream) mutex_lock(&oxfw->mutex); - if (amdtp_streaming_error(&oxfw->rx_stream)) - oxfw_stop_stream(oxfw); - - if (!amdtp_stream_running(&oxfw->rx_stream)) { - err = cmp_connection_establish(&oxfw->in_conn, - amdtp_stream_get_max_payload(&oxfw->rx_stream)); - if (err < 0) - goto err_mutex; + snd_oxfw_stream_stop_simplex(oxfw); - err = amdtp_stream_start(&oxfw->rx_stream, - oxfw->in_conn.resources.channel, - oxfw->in_conn.speed); - if (err < 0) - goto err_connection; - } - - mutex_unlock(&oxfw->mutex); + err = snd_oxfw_stream_start_simplex(oxfw); + if (err < 0) + goto end; amdtp_stream_pcm_prepare(&oxfw->rx_stream); - - return 0; - -err_connection: - cmp_connection_break(&oxfw->in_conn); -err_mutex: +end: mutex_unlock(&oxfw->mutex); - return err; } @@ -615,9 +552,6 @@ static void oxfw_card_free(struct snd_card *card) { struct snd_oxfw *oxfw = card->private_data; - amdtp_stream_destroy(&oxfw->rx_stream); - cmp_connection_destroy(&oxfw->in_conn); - fw_unit_put(oxfw->unit); mutex_destroy(&oxfw->mutex); } @@ -635,23 +569,13 @@ static int oxfw_probe(struct fw_unit *unit, if (err < 0) return err; + card->private_free = oxfw_card_free; oxfw = card->private_data; oxfw->card = card; mutex_init(&oxfw->mutex); - oxfw->unit = fw_unit_get(unit); + oxfw->unit = unit; oxfw->device_info = (const struct device_info *)id->driver_data; - err = cmp_connection_init(&oxfw->in_conn, unit, CMP_INPUT, 0); - if (err < 0) - goto err_unit; - - err = amdtp_stream_init(&oxfw->rx_stream, unit, AMDTP_OUT_STREAM, - CIP_NONBLOCKING); - if (err < 0) - goto err_connection; - - card->private_free = oxfw_card_free; - strcpy(card->driver, oxfw->device_info->driver_name); strcpy(card->shortname, oxfw->device_info->short_name); firmware = oxfw_read_firmware_version(unit); @@ -671,19 +595,18 @@ static int oxfw_probe(struct fw_unit *unit, if (err < 0) goto error; - err = snd_card_register(card); + err = snd_oxfw_stream_init_simplex(oxfw); if (err < 0) goto error; + err = snd_card_register(card); + if (err < 0) { + snd_oxfw_stream_destroy_simplex(oxfw); + goto error; + } dev_set_drvdata(&unit->device, oxfw); return 0; - -err_connection: - cmp_connection_destroy(&oxfw->in_conn); -err_unit: - fw_unit_put(oxfw->unit); - mutex_destroy(&oxfw->mutex); error: snd_card_free(card); return err; @@ -695,27 +618,18 @@ static void oxfw_bus_reset(struct fw_unit *unit) fcp_bus_reset(oxfw->unit); - if (cmp_connection_update(&oxfw->in_conn) < 0) { - amdtp_stream_pcm_abort(&oxfw->rx_stream); - mutex_lock(&oxfw->mutex); - oxfw_stop_stream(oxfw); - mutex_unlock(&oxfw->mutex); - return; - } - - amdtp_stream_update(&oxfw->rx_stream); + mutex_lock(&oxfw->mutex); + snd_oxfw_stream_update_simplex(oxfw); + mutex_unlock(&oxfw->mutex); } static void oxfw_remove(struct fw_unit *unit) { struct snd_oxfw *oxfw = dev_get_drvdata(&unit->device); - amdtp_stream_pcm_abort(&oxfw->rx_stream); snd_card_disconnect(oxfw->card); - mutex_lock(&oxfw->mutex); - oxfw_stop_stream(oxfw); - mutex_unlock(&oxfw->mutex); + snd_oxfw_stream_destroy_simplex(oxfw); snd_card_free_when_closed(oxfw->card); } diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h new file mode 100644 index 000000000000..e5836e02b48c --- /dev/null +++ b/sound/firewire/oxfw/oxfw.h @@ -0,0 +1,56 @@ +/* + * oxfw.h - a part of driver for OXFW970/971 based devices + * + * Copyright (c) Clemens Ladisch + * Licensed under the terms of the GNU General Public License, version 2. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../lib.h" +#include "../fcp.h" +#include "../packets-buffer.h" +#include "../iso-resources.h" +#include "../amdtp.h" +#include "../cmp.h" + +struct device_info { + const char *driver_name; + const char *short_name; + const char *long_name; + int (*pcm_constraints)(struct snd_pcm_runtime *runtime); + unsigned int mixer_channels; + u8 mute_fb_id; + u8 volume_fb_id; +}; + +struct snd_oxfw { + struct snd_card *card; + struct fw_unit *unit; + const struct device_info *device_info; + struct mutex mutex; + struct cmp_connection in_conn; + struct amdtp_stream rx_stream; + bool mute; + s16 volume[6]; + s16 volume_min; + s16 volume_max; +}; + +int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw); +int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw); +void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw); +void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw); +void snd_oxfw_stream_update_simplex(struct snd_oxfw *oxfw); -- cgit v1.2.3 From 3713d93a6a12f8629c2660bb4a30d48b98105fca Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sat, 29 Nov 2014 00:59:28 +0900 Subject: ALSA: oxfw: Split PCM functionality to a new file This is a help for works in followed patches. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/oxfw/Makefile | 2 +- sound/firewire/oxfw/oxfw-pcm.c | 249 +++++++++++++++++++++++++++++++++++++++++ sound/firewire/oxfw/oxfw.c | 240 +-------------------------------------- sound/firewire/oxfw/oxfw.h | 4 + 4 files changed, 255 insertions(+), 240 deletions(-) create mode 100644 sound/firewire/oxfw/oxfw-pcm.c (limited to 'sound') diff --git a/sound/firewire/oxfw/Makefile b/sound/firewire/oxfw/Makefile index e15c4c07b49d..7fb4d09a5f07 100644 --- a/sound/firewire/oxfw/Makefile +++ b/sound/firewire/oxfw/Makefile @@ -1,2 +1,2 @@ -snd-oxfw-objs := oxfw-stream.o oxfw.o +snd-oxfw-objs := oxfw-stream.o oxfw-pcm.o oxfw.o obj-m += snd-oxfw.o diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c new file mode 100644 index 000000000000..d39f17a8f8c0 --- /dev/null +++ b/sound/firewire/oxfw/oxfw-pcm.c @@ -0,0 +1,249 @@ +/* + * oxfw_pcm.c - a part of driver for OXFW970/971 based devices + * + * Copyright (c) Clemens Ladisch + * Licensed under the terms of the GNU General Public License, version 2. + */ + +#include "oxfw.h" + +static int firewave_rate_constraint(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + static unsigned int stereo_rates[] = { 48000, 96000 }; + struct snd_interval *channels = + hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_interval *rate = + hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + + /* two channels work only at 48/96 kHz */ + if (snd_interval_max(channels) < 6) + return snd_interval_list(rate, 2, stereo_rates, 0); + return 0; +} + +static int firewave_channels_constraint(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + static const struct snd_interval all_channels = { .min = 6, .max = 6 }; + struct snd_interval *rate = + hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = + hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + + /* 32/44.1 kHz work only with all six channels */ + if (snd_interval_max(rate) < 48000) + return snd_interval_refine(channels, &all_channels); + return 0; +} + +int firewave_constraints(struct snd_pcm_runtime *runtime) +{ + static unsigned int channels_list[] = { 2, 6 }; + static struct snd_pcm_hw_constraint_list channels_list_constraint = { + .count = 2, + .list = channels_list, + }; + int err; + + runtime->hw.rates = SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_96000; + runtime->hw.channels_max = 6; + + err = snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, + &channels_list_constraint); + if (err < 0) + return err; + err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + firewave_rate_constraint, NULL, + SNDRV_PCM_HW_PARAM_CHANNELS, -1); + if (err < 0) + return err; + err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + firewave_channels_constraint, NULL, + SNDRV_PCM_HW_PARAM_RATE, -1); + if (err < 0) + return err; + + return 0; +} + +int lacie_speakers_constraints(struct snd_pcm_runtime *runtime) +{ + runtime->hw.rates = SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000; + + return 0; +} + +static int pcm_open(struct snd_pcm_substream *substream) +{ + static const struct snd_pcm_hardware hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_BATCH | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER, + .formats = AMDTP_OUT_PCM_FORMAT_BITS, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 4 * 1024 * 1024, + .period_bytes_min = 1, + .period_bytes_max = UINT_MAX, + .periods_min = 1, + .periods_max = UINT_MAX, + }; + struct snd_oxfw *oxfw = substream->private_data; + struct snd_pcm_runtime *runtime = substream->runtime; + bool used; + int err; + + err = cmp_connection_check_used(&oxfw->in_conn, &used); + if ((err < 0) || used) + goto end; + + runtime->hw = hardware; + + err = oxfw->device_info->pcm_constraints(runtime); + if (err < 0) + goto end; + err = snd_pcm_limit_hw_rates(runtime); + if (err < 0) + goto end; + + err = amdtp_stream_add_pcm_hw_constraints(&oxfw->rx_stream, runtime); +end: + return err; +} + +static int pcm_close(struct snd_pcm_substream *substream) +{ + return 0; +} + +static int pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct snd_oxfw *oxfw = substream->private_data; + int err; + + mutex_lock(&oxfw->mutex); + + snd_oxfw_stream_stop_simplex(oxfw); + + err = snd_pcm_lib_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); + if (err < 0) + goto error; + + amdtp_stream_set_parameters(&oxfw->rx_stream, + params_rate(hw_params), + params_channels(hw_params), + 0); + + amdtp_stream_set_pcm_format(&oxfw->rx_stream, + params_format(hw_params)); + + err = avc_general_set_sig_fmt(oxfw->unit, params_rate(hw_params), + AVC_GENERAL_PLUG_DIR_IN, 0); + if (err < 0) { + dev_err(&oxfw->unit->device, "failed to set sample rate\n"); + goto err_buffer; + } + + return 0; + +err_buffer: + snd_pcm_lib_free_vmalloc_buffer(substream); +error: + mutex_unlock(&oxfw->mutex); + return err; +} + +static int pcm_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_oxfw *oxfw = substream->private_data; + + mutex_lock(&oxfw->mutex); + snd_oxfw_stream_stop_simplex(oxfw); + mutex_unlock(&oxfw->mutex); + + return snd_pcm_lib_free_vmalloc_buffer(substream); +} + +static int pcm_prepare(struct snd_pcm_substream *substream) +{ + struct snd_oxfw *oxfw = substream->private_data; + int err; + + mutex_lock(&oxfw->mutex); + + snd_oxfw_stream_stop_simplex(oxfw); + + err = snd_oxfw_stream_start_simplex(oxfw); + if (err < 0) + goto end; + + amdtp_stream_pcm_prepare(&oxfw->rx_stream); +end: + mutex_unlock(&oxfw->mutex); + return err; +} + +static int pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_oxfw *oxfw = substream->private_data; + struct snd_pcm_substream *pcm; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + pcm = substream; + break; + case SNDRV_PCM_TRIGGER_STOP: + pcm = NULL; + break; + default: + return -EINVAL; + } + amdtp_stream_pcm_trigger(&oxfw->rx_stream, pcm); + return 0; +} + +static snd_pcm_uframes_t pcm_pointer(struct snd_pcm_substream *substream) +{ + struct snd_oxfw *oxfw = substream->private_data; + + return amdtp_stream_pcm_pointer(&oxfw->rx_stream); +} + +int snd_oxfw_create_pcm(struct snd_oxfw *oxfw) +{ + static struct snd_pcm_ops ops = { + .open = pcm_open, + .close = pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = pcm_hw_params, + .hw_free = pcm_hw_free, + .prepare = pcm_prepare, + .trigger = pcm_trigger, + .pointer = pcm_pointer, + .page = snd_pcm_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, + }; + struct snd_pcm *pcm; + int err; + + err = snd_pcm_new(oxfw->card, oxfw->card->driver, 0, 1, 0, &pcm); + if (err < 0) + return err; + pcm->private_data = oxfw; + strcpy(pcm->name, oxfw->card->shortname); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ops); + return 0; +} diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 40556677ea07..24bb6dff23cc 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -25,244 +25,6 @@ MODULE_AUTHOR("Clemens Ladisch "); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("snd-firewire-speakers"); -static int firewave_rate_constraint(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - static unsigned int stereo_rates[] = { 48000, 96000 }; - struct snd_interval *channels = - hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_interval *rate = - hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); - - /* two channels work only at 48/96 kHz */ - if (snd_interval_max(channels) < 6) - return snd_interval_list(rate, 2, stereo_rates, 0); - return 0; -} - -static int firewave_channels_constraint(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - static const struct snd_interval all_channels = { .min = 6, .max = 6 }; - struct snd_interval *rate = - hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *channels = - hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - - /* 32/44.1 kHz work only with all six channels */ - if (snd_interval_max(rate) < 48000) - return snd_interval_refine(channels, &all_channels); - return 0; -} - -static int firewave_constraints(struct snd_pcm_runtime *runtime) -{ - static unsigned int channels_list[] = { 2, 6 }; - static struct snd_pcm_hw_constraint_list channels_list_constraint = { - .count = 2, - .list = channels_list, - }; - int err; - - runtime->hw.rates = SNDRV_PCM_RATE_32000 | - SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_96000; - runtime->hw.channels_max = 6; - - err = snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, - &channels_list_constraint); - if (err < 0) - return err; - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - firewave_rate_constraint, NULL, - SNDRV_PCM_HW_PARAM_CHANNELS, -1); - if (err < 0) - return err; - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - firewave_channels_constraint, NULL, - SNDRV_PCM_HW_PARAM_RATE, -1); - if (err < 0) - return err; - - return 0; -} - -static int lacie_speakers_constraints(struct snd_pcm_runtime *runtime) -{ - runtime->hw.rates = SNDRV_PCM_RATE_32000 | - SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_88200 | - SNDRV_PCM_RATE_96000; - - return 0; -} - -static int oxfw_open(struct snd_pcm_substream *substream) -{ - static const struct snd_pcm_hardware hardware = { - .info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_BATCH | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER, - .formats = AMDTP_OUT_PCM_FORMAT_BITS, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = 4 * 1024 * 1024, - .period_bytes_min = 1, - .period_bytes_max = UINT_MAX, - .periods_min = 1, - .periods_max = UINT_MAX, - }; - struct snd_oxfw *oxfw = substream->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; - int err; - - runtime->hw = hardware; - - err = oxfw->device_info->pcm_constraints(runtime); - if (err < 0) - return err; - err = snd_pcm_limit_hw_rates(runtime); - if (err < 0) - return err; - - err = amdtp_stream_add_pcm_hw_constraints(&oxfw->rx_stream, runtime); - if (err < 0) - return err; - - return 0; -} - -static int oxfw_close(struct snd_pcm_substream *substream) -{ - return 0; -} - -static int oxfw_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct snd_oxfw *oxfw = substream->private_data; - int err; - - mutex_lock(&oxfw->mutex); - - snd_oxfw_stream_stop_simplex(oxfw); - - err = snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); - if (err < 0) - goto error; - - amdtp_stream_set_parameters(&oxfw->rx_stream, - params_rate(hw_params), - params_channels(hw_params), - 0); - - amdtp_stream_set_pcm_format(&oxfw->rx_stream, - params_format(hw_params)); - - err = avc_general_set_sig_fmt(oxfw->unit, params_rate(hw_params), - AVC_GENERAL_PLUG_DIR_IN, 0); - if (err < 0) { - dev_err(&oxfw->unit->device, "failed to set sample rate\n"); - goto err_buffer; - } - - return 0; - -err_buffer: - snd_pcm_lib_free_vmalloc_buffer(substream); -error: - mutex_unlock(&oxfw->mutex); - return err; -} - -static int oxfw_hw_free(struct snd_pcm_substream *substream) -{ - struct snd_oxfw *oxfw = substream->private_data; - - mutex_lock(&oxfw->mutex); - snd_oxfw_stream_stop_simplex(oxfw); - mutex_unlock(&oxfw->mutex); - - return snd_pcm_lib_free_vmalloc_buffer(substream); -} - -static int oxfw_prepare(struct snd_pcm_substream *substream) -{ - struct snd_oxfw *oxfw = substream->private_data; - int err; - - mutex_lock(&oxfw->mutex); - - snd_oxfw_stream_stop_simplex(oxfw); - - err = snd_oxfw_stream_start_simplex(oxfw); - if (err < 0) - goto end; - - amdtp_stream_pcm_prepare(&oxfw->rx_stream); -end: - mutex_unlock(&oxfw->mutex); - return err; -} - -static int oxfw_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct snd_oxfw *oxfw = substream->private_data; - struct snd_pcm_substream *pcm; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - pcm = substream; - break; - case SNDRV_PCM_TRIGGER_STOP: - pcm = NULL; - break; - default: - return -EINVAL; - } - amdtp_stream_pcm_trigger(&oxfw->rx_stream, pcm); - return 0; -} - -static snd_pcm_uframes_t oxfw_pointer(struct snd_pcm_substream *substream) -{ - struct snd_oxfw *oxfw = substream->private_data; - - return amdtp_stream_pcm_pointer(&oxfw->rx_stream); -} - -static int oxfw_create_pcm(struct snd_oxfw *oxfw) -{ - static struct snd_pcm_ops ops = { - .open = oxfw_open, - .close = oxfw_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = oxfw_hw_params, - .hw_free = oxfw_hw_free, - .prepare = oxfw_prepare, - .trigger = oxfw_trigger, - .pointer = oxfw_pointer, - .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, - }; - struct snd_pcm *pcm; - int err; - - err = snd_pcm_new(oxfw->card, "OXFW", 0, 1, 0, &pcm); - if (err < 0) - return err; - pcm->private_data = oxfw; - strcpy(pcm->name, oxfw->device_info->short_name); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ops); - return 0; -} - enum control_action { CTL_READ, CTL_WRITE }; enum control_attribute { CTL_MIN = 0x02, @@ -587,7 +349,7 @@ static int oxfw_probe(struct fw_unit *unit, dev_name(&unit->device), 100 << fw_dev->max_speed); strcpy(card->mixername, "OXFW"); - err = oxfw_create_pcm(oxfw); + err = snd_oxfw_create_pcm(oxfw); if (err < 0) goto error; diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index e5836e02b48c..1196db8a6300 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -54,3 +54,7 @@ int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw); void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw); void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw); void snd_oxfw_stream_update_simplex(struct snd_oxfw *oxfw); + +int firewave_constraints(struct snd_pcm_runtime *runtime); +int lacie_speakers_constraints(struct snd_pcm_runtime *runtime); +int snd_oxfw_create_pcm(struct snd_oxfw *oxfw); -- cgit v1.2.3 From 31514bfb4ab8ba6f93b5ce5fcc543cb2ac4f96e5 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sat, 29 Nov 2014 00:59:29 +0900 Subject: ALSA: oxfw: Split control functionality to a new file This is a help for works in followed patches. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/oxfw/Makefile | 2 +- sound/firewire/oxfw/oxfw-control.c | 283 +++++++++++++++++++++++++++++++++++++ sound/firewire/oxfw/oxfw.c | 277 +----------------------------------- sound/firewire/oxfw/oxfw.h | 2 + 4 files changed, 287 insertions(+), 277 deletions(-) create mode 100644 sound/firewire/oxfw/oxfw-control.c (limited to 'sound') diff --git a/sound/firewire/oxfw/Makefile b/sound/firewire/oxfw/Makefile index 7fb4d09a5f07..0cf48fd87688 100644 --- a/sound/firewire/oxfw/Makefile +++ b/sound/firewire/oxfw/Makefile @@ -1,2 +1,2 @@ -snd-oxfw-objs := oxfw-stream.o oxfw-pcm.o oxfw.o +snd-oxfw-objs := oxfw-stream.o oxfw-control.o oxfw-pcm.o oxfw.o obj-m += snd-oxfw.o diff --git a/sound/firewire/oxfw/oxfw-control.c b/sound/firewire/oxfw/oxfw-control.c new file mode 100644 index 000000000000..02a1cb90f20d --- /dev/null +++ b/sound/firewire/oxfw/oxfw-control.c @@ -0,0 +1,283 @@ +/* + * oxfw_stream.c - a part of driver for OXFW970/971 based devices + * + * Copyright (c) Clemens Ladisch + * Licensed under the terms of the GNU General Public License, version 2. + */ + +#include "oxfw.h" + +enum control_action { CTL_READ, CTL_WRITE }; +enum control_attribute { + CTL_MIN = 0x02, + CTL_MAX = 0x03, + CTL_CURRENT = 0x10, +}; + +static int oxfw_mute_command(struct snd_oxfw *oxfw, bool *value, + enum control_action action) +{ + u8 *buf; + u8 response_ok; + int err; + + buf = kmalloc(11, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (action == CTL_READ) { + buf[0] = 0x01; /* AV/C, STATUS */ + response_ok = 0x0c; /* STABLE */ + } else { + buf[0] = 0x00; /* AV/C, CONTROL */ + response_ok = 0x09; /* ACCEPTED */ + } + buf[1] = 0x08; /* audio unit 0 */ + buf[2] = 0xb8; /* FUNCTION BLOCK */ + buf[3] = 0x81; /* function block type: feature */ + buf[4] = oxfw->device_info->mute_fb_id; /* function block ID */ + buf[5] = 0x10; /* control attribute: current */ + buf[6] = 0x02; /* selector length */ + buf[7] = 0x00; /* audio channel number */ + buf[8] = 0x01; /* control selector: mute */ + buf[9] = 0x01; /* control data length */ + if (action == CTL_READ) + buf[10] = 0xff; + else + buf[10] = *value ? 0x70 : 0x60; + + err = fcp_avc_transaction(oxfw->unit, buf, 11, buf, 11, 0x3fe); + if (err < 0) + goto error; + if (err < 11) { + dev_err(&oxfw->unit->device, "short FCP response\n"); + err = -EIO; + goto error; + } + if (buf[0] != response_ok) { + dev_err(&oxfw->unit->device, "mute command failed\n"); + err = -EIO; + goto error; + } + if (action == CTL_READ) + *value = buf[10] == 0x70; + + err = 0; + +error: + kfree(buf); + + return err; +} + +static int oxfw_volume_command(struct snd_oxfw *oxfw, s16 *value, + unsigned int channel, + enum control_attribute attribute, + enum control_action action) +{ + u8 *buf; + u8 response_ok; + int err; + + buf = kmalloc(12, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (action == CTL_READ) { + buf[0] = 0x01; /* AV/C, STATUS */ + response_ok = 0x0c; /* STABLE */ + } else { + buf[0] = 0x00; /* AV/C, CONTROL */ + response_ok = 0x09; /* ACCEPTED */ + } + buf[1] = 0x08; /* audio unit 0 */ + buf[2] = 0xb8; /* FUNCTION BLOCK */ + buf[3] = 0x81; /* function block type: feature */ + buf[4] = oxfw->device_info->volume_fb_id; /* function block ID */ + buf[5] = attribute; /* control attribute */ + buf[6] = 0x02; /* selector length */ + buf[7] = channel; /* audio channel number */ + buf[8] = 0x02; /* control selector: volume */ + buf[9] = 0x02; /* control data length */ + if (action == CTL_READ) { + buf[10] = 0xff; + buf[11] = 0xff; + } else { + buf[10] = *value >> 8; + buf[11] = *value; + } + + err = fcp_avc_transaction(oxfw->unit, buf, 12, buf, 12, 0x3fe); + if (err < 0) + goto error; + if (err < 12) { + dev_err(&oxfw->unit->device, "short FCP response\n"); + err = -EIO; + goto error; + } + if (buf[0] != response_ok) { + dev_err(&oxfw->unit->device, "volume command failed\n"); + err = -EIO; + goto error; + } + if (action == CTL_READ) + *value = (buf[10] << 8) | buf[11]; + + err = 0; + +error: + kfree(buf); + + return err; +} + +static int oxfw_mute_get(struct snd_kcontrol *control, + struct snd_ctl_elem_value *value) +{ + struct snd_oxfw *oxfw = control->private_data; + + value->value.integer.value[0] = !oxfw->mute; + + return 0; +} + +static int oxfw_mute_put(struct snd_kcontrol *control, + struct snd_ctl_elem_value *value) +{ + struct snd_oxfw *oxfw = control->private_data; + bool mute; + int err; + + mute = !value->value.integer.value[0]; + + if (mute == oxfw->mute) + return 0; + + err = oxfw_mute_command(oxfw, &mute, CTL_WRITE); + if (err < 0) + return err; + oxfw->mute = mute; + + return 1; +} + +static int oxfw_volume_info(struct snd_kcontrol *control, + struct snd_ctl_elem_info *info) +{ + struct snd_oxfw *oxfw = control->private_data; + + info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + info->count = oxfw->device_info->mixer_channels; + info->value.integer.min = oxfw->volume_min; + info->value.integer.max = oxfw->volume_max; + + return 0; +} + +static const u8 channel_map[6] = { 0, 1, 4, 5, 2, 3 }; + +static int oxfw_volume_get(struct snd_kcontrol *control, + struct snd_ctl_elem_value *value) +{ + struct snd_oxfw *oxfw = control->private_data; + unsigned int i; + + for (i = 0; i < oxfw->device_info->mixer_channels; ++i) + value->value.integer.value[channel_map[i]] = oxfw->volume[i]; + + return 0; +} + +static int oxfw_volume_put(struct snd_kcontrol *control, + struct snd_ctl_elem_value *value) +{ + struct snd_oxfw *oxfw = control->private_data; + unsigned int i, changed_channels; + bool equal_values = true; + s16 volume; + int err; + + for (i = 0; i < oxfw->device_info->mixer_channels; ++i) { + if (value->value.integer.value[i] < oxfw->volume_min || + value->value.integer.value[i] > oxfw->volume_max) + return -EINVAL; + if (value->value.integer.value[i] != + value->value.integer.value[0]) + equal_values = false; + } + + changed_channels = 0; + for (i = 0; i < oxfw->device_info->mixer_channels; ++i) + if (value->value.integer.value[channel_map[i]] != + oxfw->volume[i]) + changed_channels |= 1 << (i + 1); + + if (equal_values && changed_channels != 0) + changed_channels = 1 << 0; + + for (i = 0; i <= oxfw->device_info->mixer_channels; ++i) { + volume = value->value.integer.value[channel_map[i ? i - 1 : 0]]; + if (changed_channels & (1 << i)) { + err = oxfw_volume_command(oxfw, &volume, i, + CTL_CURRENT, CTL_WRITE); + if (err < 0) + return err; + } + if (i > 0) + oxfw->volume[i - 1] = volume; + } + + return changed_channels != 0; +} + +int snd_oxfw_create_mixer(struct snd_oxfw *oxfw) +{ + static const struct snd_kcontrol_new controls[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "PCM Playback Switch", + .info = snd_ctl_boolean_mono_info, + .get = oxfw_mute_get, + .put = oxfw_mute_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "PCM Playback Volume", + .info = oxfw_volume_info, + .get = oxfw_volume_get, + .put = oxfw_volume_put, + }, + }; + unsigned int i, first_ch; + int err; + + err = oxfw_volume_command(oxfw, &oxfw->volume_min, + 0, CTL_MIN, CTL_READ); + if (err < 0) + return err; + err = oxfw_volume_command(oxfw, &oxfw->volume_max, + 0, CTL_MAX, CTL_READ); + if (err < 0) + return err; + + err = oxfw_mute_command(oxfw, &oxfw->mute, CTL_READ); + if (err < 0) + return err; + + first_ch = oxfw->device_info->mixer_channels == 1 ? 0 : 1; + for (i = 0; i < oxfw->device_info->mixer_channels; ++i) { + err = oxfw_volume_command(oxfw, &oxfw->volume[i], + first_ch + i, CTL_CURRENT, CTL_READ); + if (err < 0) + return err; + } + + for (i = 0; i < ARRAY_SIZE(controls); ++i) { + err = snd_ctl_add(oxfw->card, + snd_ctl_new1(&controls[i], oxfw)); + if (err < 0) + return err; + } + + return 0; +} diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 24bb6dff23cc..951d9a4e2102 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -25,281 +25,6 @@ MODULE_AUTHOR("Clemens Ladisch "); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("snd-firewire-speakers"); -enum control_action { CTL_READ, CTL_WRITE }; -enum control_attribute { - CTL_MIN = 0x02, - CTL_MAX = 0x03, - CTL_CURRENT = 0x10, -}; - -static int oxfw_mute_command(struct snd_oxfw *oxfw, bool *value, - enum control_action action) -{ - u8 *buf; - u8 response_ok; - int err; - - buf = kmalloc(11, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - if (action == CTL_READ) { - buf[0] = 0x01; /* AV/C, STATUS */ - response_ok = 0x0c; /* STABLE */ - } else { - buf[0] = 0x00; /* AV/C, CONTROL */ - response_ok = 0x09; /* ACCEPTED */ - } - buf[1] = 0x08; /* audio unit 0 */ - buf[2] = 0xb8; /* FUNCTION BLOCK */ - buf[3] = 0x81; /* function block type: feature */ - buf[4] = oxfw->device_info->mute_fb_id; /* function block ID */ - buf[5] = 0x10; /* control attribute: current */ - buf[6] = 0x02; /* selector length */ - buf[7] = 0x00; /* audio channel number */ - buf[8] = 0x01; /* control selector: mute */ - buf[9] = 0x01; /* control data length */ - if (action == CTL_READ) - buf[10] = 0xff; - else - buf[10] = *value ? 0x70 : 0x60; - - err = fcp_avc_transaction(oxfw->unit, buf, 11, buf, 11, 0x3fe); - if (err < 0) - goto error; - if (err < 11) { - dev_err(&oxfw->unit->device, "short FCP response\n"); - err = -EIO; - goto error; - } - if (buf[0] != response_ok) { - dev_err(&oxfw->unit->device, "mute command failed\n"); - err = -EIO; - goto error; - } - if (action == CTL_READ) - *value = buf[10] == 0x70; - - err = 0; - -error: - kfree(buf); - - return err; -} - -static int oxfw_volume_command(struct snd_oxfw *oxfw, s16 *value, - unsigned int channel, - enum control_attribute attribute, - enum control_action action) -{ - u8 *buf; - u8 response_ok; - int err; - - buf = kmalloc(12, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - if (action == CTL_READ) { - buf[0] = 0x01; /* AV/C, STATUS */ - response_ok = 0x0c; /* STABLE */ - } else { - buf[0] = 0x00; /* AV/C, CONTROL */ - response_ok = 0x09; /* ACCEPTED */ - } - buf[1] = 0x08; /* audio unit 0 */ - buf[2] = 0xb8; /* FUNCTION BLOCK */ - buf[3] = 0x81; /* function block type: feature */ - buf[4] = oxfw->device_info->volume_fb_id; /* function block ID */ - buf[5] = attribute; /* control attribute */ - buf[6] = 0x02; /* selector length */ - buf[7] = channel; /* audio channel number */ - buf[8] = 0x02; /* control selector: volume */ - buf[9] = 0x02; /* control data length */ - if (action == CTL_READ) { - buf[10] = 0xff; - buf[11] = 0xff; - } else { - buf[10] = *value >> 8; - buf[11] = *value; - } - - err = fcp_avc_transaction(oxfw->unit, buf, 12, buf, 12, 0x3fe); - if (err < 0) - goto error; - if (err < 12) { - dev_err(&oxfw->unit->device, "short FCP response\n"); - err = -EIO; - goto error; - } - if (buf[0] != response_ok) { - dev_err(&oxfw->unit->device, "volume command failed\n"); - err = -EIO; - goto error; - } - if (action == CTL_READ) - *value = (buf[10] << 8) | buf[11]; - - err = 0; - -error: - kfree(buf); - - return err; -} - -static int oxfw_mute_get(struct snd_kcontrol *control, - struct snd_ctl_elem_value *value) -{ - struct snd_oxfw *oxfw = control->private_data; - - value->value.integer.value[0] = !oxfw->mute; - - return 0; -} - -static int oxfw_mute_put(struct snd_kcontrol *control, - struct snd_ctl_elem_value *value) -{ - struct snd_oxfw *oxfw = control->private_data; - bool mute; - int err; - - mute = !value->value.integer.value[0]; - - if (mute == oxfw->mute) - return 0; - - err = oxfw_mute_command(oxfw, &mute, CTL_WRITE); - if (err < 0) - return err; - oxfw->mute = mute; - - return 1; -} - -static int oxfw_volume_info(struct snd_kcontrol *control, - struct snd_ctl_elem_info *info) -{ - struct snd_oxfw *oxfw = control->private_data; - - info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - info->count = oxfw->device_info->mixer_channels; - info->value.integer.min = oxfw->volume_min; - info->value.integer.max = oxfw->volume_max; - - return 0; -} - -static const u8 channel_map[6] = { 0, 1, 4, 5, 2, 3 }; - -static int oxfw_volume_get(struct snd_kcontrol *control, - struct snd_ctl_elem_value *value) -{ - struct snd_oxfw *oxfw = control->private_data; - unsigned int i; - - for (i = 0; i < oxfw->device_info->mixer_channels; ++i) - value->value.integer.value[channel_map[i]] = oxfw->volume[i]; - - return 0; -} - -static int oxfw_volume_put(struct snd_kcontrol *control, - struct snd_ctl_elem_value *value) -{ - struct snd_oxfw *oxfw = control->private_data; - unsigned int i, changed_channels; - bool equal_values = true; - s16 volume; - int err; - - for (i = 0; i < oxfw->device_info->mixer_channels; ++i) { - if (value->value.integer.value[i] < oxfw->volume_min || - value->value.integer.value[i] > oxfw->volume_max) - return -EINVAL; - if (value->value.integer.value[i] != - value->value.integer.value[0]) - equal_values = false; - } - - changed_channels = 0; - for (i = 0; i < oxfw->device_info->mixer_channels; ++i) - if (value->value.integer.value[channel_map[i]] != - oxfw->volume[i]) - changed_channels |= 1 << (i + 1); - - if (equal_values && changed_channels != 0) - changed_channels = 1 << 0; - - for (i = 0; i <= oxfw->device_info->mixer_channels; ++i) { - volume = value->value.integer.value[channel_map[i ? i - 1 : 0]]; - if (changed_channels & (1 << i)) { - err = oxfw_volume_command(oxfw, &volume, i, - CTL_CURRENT, CTL_WRITE); - if (err < 0) - return err; - } - if (i > 0) - oxfw->volume[i - 1] = volume; - } - - return changed_channels != 0; -} - -static int oxfw_create_mixer(struct snd_oxfw *oxfw) -{ - static const struct snd_kcontrol_new controls[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Playback Switch", - .info = snd_ctl_boolean_mono_info, - .get = oxfw_mute_get, - .put = oxfw_mute_put, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Playback Volume", - .info = oxfw_volume_info, - .get = oxfw_volume_get, - .put = oxfw_volume_put, - }, - }; - unsigned int i, first_ch; - int err; - - err = oxfw_volume_command(oxfw, &oxfw->volume_min, - 0, CTL_MIN, CTL_READ); - if (err < 0) - return err; - err = oxfw_volume_command(oxfw, &oxfw->volume_max, - 0, CTL_MAX, CTL_READ); - if (err < 0) - return err; - - err = oxfw_mute_command(oxfw, &oxfw->mute, CTL_READ); - if (err < 0) - return err; - - first_ch = oxfw->device_info->mixer_channels == 1 ? 0 : 1; - for (i = 0; i < oxfw->device_info->mixer_channels; ++i) { - err = oxfw_volume_command(oxfw, &oxfw->volume[i], - first_ch + i, CTL_CURRENT, CTL_READ); - if (err < 0) - return err; - } - - for (i = 0; i < ARRAY_SIZE(controls); ++i) { - err = snd_ctl_add(oxfw->card, - snd_ctl_new1(&controls[i], oxfw)); - if (err < 0) - return err; - } - - return 0; -} - static u32 oxfw_read_firmware_version(struct fw_unit *unit) { __be32 data; @@ -353,7 +78,7 @@ static int oxfw_probe(struct fw_unit *unit, if (err < 0) goto error; - err = oxfw_create_mixer(oxfw); + err = snd_oxfw_create_mixer(oxfw); if (err < 0) goto error; diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index 1196db8a6300..6164bf3e1f5a 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -58,3 +58,5 @@ void snd_oxfw_stream_update_simplex(struct snd_oxfw *oxfw); int firewave_constraints(struct snd_pcm_runtime *runtime); int lacie_speakers_constraints(struct snd_pcm_runtime *runtime); int snd_oxfw_create_pcm(struct snd_oxfw *oxfw); + +int snd_oxfw_create_mixer(struct snd_oxfw *oxfw); -- cgit v1.2.3 From 316638a5030a04bb3259dcbca0632281001a4b24 Mon Sep 17 00:00:00 2001 From: Kyle Chamberlin Date: Fri, 28 Nov 2014 13:59:56 -0500 Subject: ALSA: virmidi: fixed code style issues Fixed some minor code style issues and also removed some assignments inside of if conditionals. Signed-off-by: Kyle Chamberlin Signed-off-by: Takashi Iwai --- sound/drivers/virmidi.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/drivers/virmidi.c b/sound/drivers/virmidi.c index b178724295f3..0af88d926793 100644 --- a/sound/drivers/virmidi.c +++ b/sound/drivers/virmidi.c @@ -99,30 +99,33 @@ static int snd_virmidi_probe(struct platform_device *devptr) if (midi_devs[dev] > MAX_MIDI_DEVICES) { snd_printk(KERN_WARNING - "too much midi devices for virmidi %d: " - "force to use %d\n", dev, MAX_MIDI_DEVICES); + "too much midi devices for virmidi %d: force to use %d\n", + dev, MAX_MIDI_DEVICES); midi_devs[dev] = MAX_MIDI_DEVICES; } for (idx = 0; idx < midi_devs[dev]; idx++) { struct snd_rawmidi *rmidi; struct snd_virmidi_dev *rdev; - if ((err = snd_virmidi_new(card, idx, &rmidi)) < 0) + + err = snd_virmidi_new(card, idx, &rmidi); + if (err < 0) goto __nodev; rdev = rmidi->private_data; vmidi->midi[idx] = rmidi; strcpy(rmidi->name, "Virtual Raw MIDI"); rdev->seq_mode = SNDRV_VIRMIDI_SEQ_DISPATCH; } - + strcpy(card->driver, "VirMIDI"); strcpy(card->shortname, "VirMIDI"); sprintf(card->longname, "Virtual MIDI Card %i", dev + 1); - if ((err = snd_card_register(card)) == 0) { + err = snd_card_register(card); + if (err) { platform_set_drvdata(devptr, card); return 0; } - __nodev: +__nodev: snd_card_free(card); return err; } @@ -157,13 +160,15 @@ static int __init alsa_card_virmidi_init(void) { int i, cards, err; - if ((err = platform_driver_register(&snd_virmidi_driver)) < 0) + err = platform_driver_register(&snd_virmidi_driver); + if (err < 0) return err; cards = 0; for (i = 0; i < SNDRV_CARDS; i++) { struct platform_device *device; - if (! enable[i]) + + if (!enable[i]) continue; device = platform_device_register_simple(SND_VIRMIDI_DRIVER, i, NULL, 0); -- cgit v1.2.3 From fc5d3c70f97ba54bf3d3b585912b0a76a78fb718 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 30 Nov 2014 20:13:16 +0100 Subject: ALSA: virmidi: Fix wrong error check While rewriting the code in the previous commit [316638a5030a: ALSA: virmidi: fixed code style issues], the error check was wrongly converted. This resulted an Oops. Fixes: 316638a5030a ('ALSA: virmidi: fixed code style issues') Reported-by: Fengguang Wu Signed-off-by: Takashi Iwai --- sound/drivers/virmidi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/drivers/virmidi.c b/sound/drivers/virmidi.c index 0af88d926793..d28d8706443c 100644 --- a/sound/drivers/virmidi.c +++ b/sound/drivers/virmidi.c @@ -121,7 +121,7 @@ static int snd_virmidi_probe(struct platform_device *devptr) sprintf(card->longname, "Virtual MIDI Card %i", dev + 1); err = snd_card_register(card); - if (err) { + if (!err) { platform_set_drvdata(devptr, card); return 0; } -- cgit v1.2.3 From dacacb0aa0cb6fdeb69313db6acfc82456945d7e Mon Sep 17 00:00:00 2001 From: Panu Matilainen Date: Sun, 30 Nov 2014 18:45:40 +0200 Subject: ALSA: usb-audio: Add support for Zoom R16/24 capture and midi interfaces This makes the midi interface and capture work out of the box with R16 (and presumably R24 too but untested). Playback stream would also seem to function fine except for one caveat: no sound is produced, so it is disabled for now. Mixer descriptors are garbage and will require further quirks to enable functionality, also disabled here. Signed-off-by: Panu Matilainen Signed-off-by: Takashi Iwai --- sound/usb/quirks-table.h | 40 ++++++++++++++++++++++++++++++++++++++++ sound/usb/quirks.c | 8 ++++++++ 2 files changed, 48 insertions(+) (limited to 'sound') diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 013cba8ee8a6..73d2ba47cc31 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -3173,6 +3173,46 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, +{ + /* + * ZOOM R16/24 in audio interface mode. + * Mixer descriptors are garbage, further quirks will be needed + * to make any of it functional, thus disabled for now. + * Playback stream appears to start and run fine but no sound + * is produced, so also disabled for now. + */ + USB_DEVICE(0x1686, 0x00dd), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + /* Mixer */ + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE, + }, + { + /* Playback */ + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE, + }, + { + /* Capture */ + .ifnum = 2, + .type = QUIRK_AUDIO_STANDARD_INTERFACE, + }, + { + /* Midi */ + .ifnum = 3, + .type = QUIRK_MIDI_STANDARD_INTERFACE + }, + { + .ifnum = -1 + }, + } + } +}, + { /* * Some USB MIDI devices don't have an audio control interface, diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index e45cc3af9b9c..4dbfb3d18ee2 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1207,6 +1207,14 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, break; } } + + /* Zoom R16/24 needs a tiny delay here, otherwise requests like + * get/set frequency return as failed despite actually succeeding. + */ + if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1686) && + (le16_to_cpu(dev->descriptor.idProduct) == 0x00dd) && + (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) + mdelay(1); } /* -- cgit v1.2.3 From ea09dd3b006b26002802b7b534bdb6531429c8ff Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Tue, 2 Dec 2014 04:03:16 +0800 Subject: ALSA: dice: fix semicolon.cocci warnings sound/firewire/dice/dice-transaction.c:34:2-3: Unneeded semicolon Removes unneeded semicolon. Generated by: scripts/coccinelle/misc/semicolon.cocci CC: Takashi Sakamoto Signed-off-by: Fengguang Wu Signed-off-by: Takashi Iwai --- sound/firewire/dice/dice-transaction.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/firewire/dice/dice-transaction.c b/sound/firewire/dice/dice-transaction.c index a9b98e087dce..1fe304c0a044 100644 --- a/sound/firewire/dice/dice-transaction.c +++ b/sound/firewire/dice/dice-transaction.c @@ -31,7 +31,7 @@ static u64 get_subaddr(struct snd_dice *dice, enum snd_dice_addr_type type, default: offset += dice->global_offset; break; - }; + } offset += DICE_PRIVATE_SPACE; return offset; } -- cgit v1.2.3 From 87164cc5723329565089a999b6671bd214caf0a0 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 2 Dec 2014 18:05:32 +0100 Subject: ALSA: asihpi: Deletion of an unnecessary check before the function call "vfree" The vfree() function performs also input parameter validation. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Takashi Iwai --- sound/pci/asihpi/hpioctl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c index e457eb80658b..6aa677e60555 100644 --- a/sound/pci/asihpi/hpioctl.c +++ b/sound/pci/asihpi/hpioctl.c @@ -547,8 +547,7 @@ void asihpi_adapter_remove(struct pci_dev *pci_dev) if (pa->irq) free_irq(pa->irq, pa); - if (pa->p_buffer) - vfree(pa->p_buffer); + vfree(pa->p_buffer); if (1) dev_info(&pci_dev->dev, -- cgit v1.2.3 From 057a4a55e703038d22bc9f2bcf8b02dc35850e16 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 2 Dec 2014 18:34:45 +0100 Subject: ALSA: echoaudio: Deletion of a check before release_and_free_resource() The release_and_free_resource() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Takashi Iwai --- sound/pci/echoaudio/echoaudio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 60e40034b991..21228adaa70c 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -1875,8 +1875,7 @@ static int snd_echo_free(struct echoaudio *chip) if (chip->dsp_registers) iounmap(chip->dsp_registers); - if (chip->iores) - release_and_free_resource(chip->iores); + release_and_free_resource(chip->iores); pci_disable_device(chip->pci); -- cgit v1.2.3 From 5c34fdf48b9522ca87372b1fae19de8f93ffd130 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 2 Dec 2014 18:52:21 +0100 Subject: ALSA: trident: Deletion of a check before snd_util_memhdr_free() The snd_util_memhdr_free() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Takashi Iwai --- sound/pci/trident/trident_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index da875dced2ef..57cd757acfe7 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c @@ -3702,8 +3702,7 @@ static int snd_trident_free(struct snd_trident *trident) free_irq(trident->irq, trident); if (trident->tlb.buffer.area) { outl(0, TRID_REG(trident, NX_TLBC)); - if (trident->tlb.memhdr) - snd_util_memhdr_free(trident->tlb.memhdr); + snd_util_memhdr_free(trident->tlb.memhdr); if (trident->tlb.silent_page.area) snd_dma_free_pages(&trident->tlb.silent_page); vfree(trident->tlb.shadow_entries); -- cgit v1.2.3 From 492a7ea0a6d3cc9c16ad5f8af832ed4278225b2e Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 2 Dec 2014 22:50:24 +0100 Subject: ALSA: i2sbus: Deletion of unnecessary checks before the function call "release_and_free_resource" The release_and_free_resource() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Takashi Iwai --- sound/aoa/soundbus/i2sbus/core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/aoa/soundbus/i2sbus/core.c b/sound/aoa/soundbus/i2sbus/core.c index a80d5ea87ccd..4e2b4fbf2496 100644 --- a/sound/aoa/soundbus/i2sbus/core.c +++ b/sound/aoa/soundbus/i2sbus/core.c @@ -79,8 +79,7 @@ static void i2sbus_release_dev(struct device *dev) if (i2sdev->out.dbdma) iounmap(i2sdev->out.dbdma); if (i2sdev->in.dbdma) iounmap(i2sdev->in.dbdma); for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) - if (i2sdev->allocated_resource[i]) - release_and_free_resource(i2sdev->allocated_resource[i]); + release_and_free_resource(i2sdev->allocated_resource[i]); free_dbdma_descriptor_ring(i2sdev, &i2sdev->out.dbdma_ring); free_dbdma_descriptor_ring(i2sdev, &i2sdev->in.dbdma_ring); for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) @@ -323,8 +322,7 @@ static int i2sbus_add_dev(struct macio_dev *macio, if (dev->out.dbdma) iounmap(dev->out.dbdma); if (dev->in.dbdma) iounmap(dev->in.dbdma); for (i=0;i<3;i++) - if (dev->allocated_resource[i]) - release_and_free_resource(dev->allocated_resource[i]); + release_and_free_resource(dev->allocated_resource[i]); mutex_destroy(&dev->lock); kfree(dev); return 0; -- cgit v1.2.3 From b42b4afb7482f1c079c82af824a7fe750590f438 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 3 Dec 2014 09:47:20 +0100 Subject: ALSA: hda - Define the DCAPS preset for the old Intel chipsets Just for improving readability. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index fc7aff0eb562..53e43d111a3b 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -276,6 +276,10 @@ enum { (((chip)->driver_caps & AZX_DCAPS_SNOOP_MASK) >> 10) #define AZX_DCAPS_SNOOP_TYPE(type) ((AZX_SNOOP_TYPE_ ## type) << 10) +/* quirks for old Intel chipsets */ +#define AZX_DCAPS_INTEL_ICH \ + (AZX_DCAPS_OLD_SSYNC | AZX_DCAPS_BUFSIZE) + /* quirks for Intel PCH */ #define AZX_DCAPS_INTEL_PCH_NOPM \ (AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY |\ @@ -2054,31 +2058,30 @@ static const struct pci_device_id azx_ids[] = { /* Braswell */ { PCI_DEVICE(0x8086, 0x2284), .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, - /* ICH */ + /* ICH6 */ { PCI_DEVICE(0x8086, 0x2668), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | - AZX_DCAPS_BUFSIZE }, /* ICH6 */ + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH }, + /* ICH7 */ { PCI_DEVICE(0x8086, 0x27d8), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | - AZX_DCAPS_BUFSIZE }, /* ICH7 */ + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH }, + /* ESB2 */ { PCI_DEVICE(0x8086, 0x269a), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | - AZX_DCAPS_BUFSIZE }, /* ESB2 */ + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH }, + /* ICH8 */ { PCI_DEVICE(0x8086, 0x284b), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | - AZX_DCAPS_BUFSIZE }, /* ICH8 */ + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH }, + /* ICH9 */ { PCI_DEVICE(0x8086, 0x293e), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | - AZX_DCAPS_BUFSIZE }, /* ICH9 */ + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH }, + /* ICH9 */ { PCI_DEVICE(0x8086, 0x293f), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | - AZX_DCAPS_BUFSIZE }, /* ICH9 */ + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH }, + /* ICH10 */ { PCI_DEVICE(0x8086, 0x3a3e), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | - AZX_DCAPS_BUFSIZE }, /* ICH10 */ + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH }, + /* ICH10 */ { PCI_DEVICE(0x8086, 0x3a6e), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | - AZX_DCAPS_BUFSIZE }, /* ICH10 */ + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH }, /* Generic Intel */ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID), .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, -- cgit v1.2.3 From 103884a351a221553095c509a1dbbbf7d4fd9b05 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 3 Dec 2014 09:56:20 +0100 Subject: ALSA: hda - Drop AZX_DCAPS_ALIGN_BUFSIZE We introduced AZX_DCAPS_ALIGN_BUFSIZE to explicity show that the controller needs the alignment, with a slight hope that the buffer size alignment will be disabled as default in future. But the reality tells that most chips need the buffer size alignment, and it'll be likely enabled in future, too. This patch drops AZX_DCAPS_ALIGN_BUFSIZE to give back one more precious DCAPS bit for future use. At the same time, rename AZX_DCAPS_BUFSIZE with AZX_DCAPS_NO_ALIGN_BUFSIZE for avoiding confusion. AZX_DCAPS_ALIGN_BUFSIZE are still kept (but commented out) in each DCAPS presets for a purpose as markers. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 16 +++++++--------- sound/pci/hda/hda_priv.h | 4 ++-- 2 files changed, 9 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 53e43d111a3b..5ac0d39d59bc 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -278,24 +278,24 @@ enum { /* quirks for old Intel chipsets */ #define AZX_DCAPS_INTEL_ICH \ - (AZX_DCAPS_OLD_SSYNC | AZX_DCAPS_BUFSIZE) + (AZX_DCAPS_OLD_SSYNC | AZX_DCAPS_NO_ALIGN_BUFSIZE) /* quirks for Intel PCH */ #define AZX_DCAPS_INTEL_PCH_NOPM \ - (AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY |\ + (AZX_DCAPS_NO_ALIGN_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY |\ AZX_DCAPS_REVERSE_ASSIGN | AZX_DCAPS_SNOOP_TYPE(SCH)) #define AZX_DCAPS_INTEL_PCH \ (AZX_DCAPS_INTEL_PCH_NOPM | AZX_DCAPS_PM_RUNTIME) #define AZX_DCAPS_INTEL_HASWELL \ - (AZX_DCAPS_ALIGN_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY |\ + (/*AZX_DCAPS_ALIGN_BUFSIZE |*/ AZX_DCAPS_COUNT_LPIB_DELAY |\ AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_POWERWELL |\ AZX_DCAPS_SNOOP_TYPE(SCH)) /* Broadwell HDMI can't use position buffer reliably, force to use LPIB */ #define AZX_DCAPS_INTEL_BROADWELL \ - (AZX_DCAPS_ALIGN_BUFSIZE | AZX_DCAPS_POSFIX_LPIB |\ + (/*AZX_DCAPS_ALIGN_BUFSIZE |*/ AZX_DCAPS_POSFIX_LPIB |\ AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_POWERWELL |\ AZX_DCAPS_SNOOP_TYPE(SCH)) @@ -315,7 +315,7 @@ enum { /* quirks for Nvidia */ #define AZX_DCAPS_PRESET_NVIDIA \ - (AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI | AZX_DCAPS_ALIGN_BUFSIZE |\ + (AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI | /*AZX_DCAPS_ALIGN_BUFSIZE |*/ \ AZX_DCAPS_NO_64BIT | AZX_DCAPS_CORBRP_SELF_CLEAR |\ AZX_DCAPS_SNOOP_TYPE(NVIDIA)) @@ -1568,10 +1568,8 @@ static int azx_first_init(struct azx *chip) if (align_buffer_size >= 0) chip->align_buffer_size = !!align_buffer_size; else { - if (chip->driver_caps & AZX_DCAPS_BUFSIZE) + if (chip->driver_caps & AZX_DCAPS_NO_ALIGN_BUFSIZE) chip->align_buffer_size = 0; - else if (chip->driver_caps & AZX_DCAPS_ALIGN_BUFSIZE) - chip->align_buffer_size = 1; else chip->align_buffer_size = 1; } @@ -2086,7 +2084,7 @@ static const struct pci_device_id azx_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID), .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, .class_mask = 0xffffff, - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_BUFSIZE }, + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_NO_ALIGN_BUFSIZE }, /* ATI SB 450/600/700/800/900 */ { PCI_DEVICE(0x1002, 0x437b), .driver_data = AZX_DRIVER_ATI | AZX_DCAPS_PRESET_ATI_SB }, diff --git a/sound/pci/hda/hda_priv.h b/sound/pci/hda/hda_priv.h index a09703a2b2c1..aa484fdf4338 100644 --- a/sound/pci/hda/hda_priv.h +++ b/sound/pci/hda/hda_priv.h @@ -162,8 +162,8 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define AZX_DCAPS_NO_64BIT (1 << 18) /* No 64bit address */ #define AZX_DCAPS_SYNC_WRITE (1 << 19) /* sync each cmd write */ #define AZX_DCAPS_OLD_SSYNC (1 << 20) /* Old SSYNC reg for ICH */ -#define AZX_DCAPS_BUFSIZE (1 << 21) /* no buffer size alignment */ -#define AZX_DCAPS_ALIGN_BUFSIZE (1 << 22) /* buffer size alignment */ +#define AZX_DCAPS_NO_ALIGN_BUFSIZE (1 << 21) /* no buffer size alignment */ +/* 22 unused */ #define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23) /* BDLE in 4k boundary */ #define AZX_DCAPS_REVERSE_ASSIGN (1 << 24) /* Assign devices in reverse order */ #define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */ -- cgit v1.2.3 From 5395103dcc709d87f08edaecb786fc37781f3b22 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 3 Dec 2014 09:59:31 -0800 Subject: ALSA: ctxfi: Neaten get_daio_rsc Move the pointer declarations into the blocks that use them. Neaten the kfree calls when the _init functions fail. Trivially reduces object size (defconfig x86-64) $ size sound/pci/ctxfi/ctdaio.o.* text data bss dec hex filename 5287 224 0 5511 1587 sound/pci/ctxfi/ctdaio.o.new 5319 224 0 5543 15a7 sound/pci/ctxfi/ctdaio.o.old Signed-off-by: Joe Perches Noticed-by: Markus Elfring Signed-off-by: Takashi Iwai --- sound/pci/ctxfi/ctdaio.c | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) (limited to 'sound') diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c index c1c3f8816fff..9b87dd28de83 100644 --- a/sound/pci/ctxfi/ctdaio.c +++ b/sound/pci/ctxfi/ctdaio.c @@ -528,8 +528,6 @@ static int get_daio_rsc(struct daio_mgr *mgr, struct daio **rdaio) { int err; - struct dai *dai = NULL; - struct dao *dao = NULL; unsigned long flags; *rdaio = NULL; @@ -544,27 +542,30 @@ static int get_daio_rsc(struct daio_mgr *mgr, return err; } + err = -ENOMEM; /* Allocate mem for daio resource */ if (desc->type <= DAIO_OUT_MAX) { - dao = kzalloc(sizeof(*dao), GFP_KERNEL); - if (!dao) { - err = -ENOMEM; + struct dao *dao = kzalloc(sizeof(*dao), GFP_KERNEL); + if (!dao) goto error; - } + err = dao_rsc_init(dao, desc, mgr); - if (err) + if (err) { + kfree(dao); goto error; + } *rdaio = &dao->daio; } else { - dai = kzalloc(sizeof(*dai), GFP_KERNEL); - if (!dai) { - err = -ENOMEM; + struct dai *dai = kzalloc(sizeof(*dai), GFP_KERNEL); + if (!dai) goto error; - } + err = dai_rsc_init(dai, desc, mgr); - if (err) + if (err) { + kfree(dai); goto error; + } *rdaio = &dai->daio; } @@ -575,11 +576,6 @@ static int get_daio_rsc(struct daio_mgr *mgr, return 0; error: - if (dao) - kfree(dao); - else if (dai) - kfree(dai); - spin_lock_irqsave(&mgr->mgr_lock, flags); daio_mgr_put_rsc(&mgr->mgr, desc->type); spin_unlock_irqrestore(&mgr->mgr_lock, flags); -- cgit v1.2.3 From ca460cc250aa9d5255b3e2469ca0abad5d136233 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Fri, 5 Dec 2014 15:42:54 +0100 Subject: ALSA: sound/atmel/ac97c.c: Fix device index for pcm chip->pdev->id is -1 by default. This is an invalid index resulting in device file names like /dev/snd/pcmC0D-1p. Signed-off-by: Alexander Stein Signed-off-by: Takashi Iwai --- sound/atmel/ac97c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c index b59427d5a697..f1d119538397 100644 --- a/sound/atmel/ac97c.c +++ b/sound/atmel/ac97c.c @@ -773,7 +773,7 @@ static int atmel_ac97c_pcm_new(struct atmel_ac97c *chip) return err; } retval = snd_pcm_new(chip->card, chip->card->shortname, - chip->pdev->id, playback, capture, &pcm); + 0, playback, capture, &pcm); if (retval) return retval; -- cgit v1.2.3 From 1132015b16580d3f53385354ffec0f58443a1ffd Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Fri, 5 Dec 2014 20:10:06 +0100 Subject: ALSA: sound/atmel/ac97c.c: Add missing clock prepare Clocks must be prepared before enabling them. Do this in one step. Replace clk_enable with clk_prepare_enable and clk_disable with clk_disable_unprepare. This fixes the following warning: ------------[ cut here ]------------ WARNING: CPU: 0 PID: 1 at drivers/clk/clk.c:895 __clk_enable+0x24/0x9c() Modules linked in: CPU: 0 PID: 1 Comm: swapper Tainted: G W 3.18.0-rc7+ #245 [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (warn_slowpath_common+0x60/0x80) [] (warn_slowpath_common) from [] (warn_slowpath_null+0x18/0x20) [] (warn_slowpath_null) from [] (__clk_enable+0x24/0x9c) [] (__clk_enable) from [] (clk_enable+0x18/0x2c) [] (clk_enable) from [] (atmel_ac97c_probe+0x154/0x694) [] (atmel_ac97c_probe) from [] (platform_drv_probe+0x48/0x94) [] (platform_drv_probe) from [] (driver_probe_device+0x138/0x350) [] (driver_probe_device) from [] (__driver_attach+0x68/0x8c) [] (__driver_attach) from [] (bus_for_each_dev+0x70/0x84) [] (bus_for_each_dev) from [] (bus_add_driver+0xfc/0x1f8) [] (bus_add_driver) from [] (driver_register+0x9c/0xe0) [] (driver_register) from [] (do_one_initcall+0x110/0x1c8) [] (do_one_initcall) from [] (kernel_init_freeable+0xf8/0x1b8) [] (kernel_init_freeable) from [] (kernel_init+0x8/0xe4) [] (kernel_init) from [] (ret_from_fork+0x14/0x24) ---[ end trace cb88537fdc8fa201 ]--- atmel_ac97c fffa0000.sound: AC'97 0 does not respond - RESET atmel_ac97c fffa0000.sound: AC'97 0 access is not valid [0xffffffff], removing mixer. ------------[ cut here ]------------ Signed-off-by: Alexander Stein Signed-off-by: Takashi Iwai --- sound/atmel/ac97c.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c index f1d119538397..cb44c74c9702 100644 --- a/sound/atmel/ac97c.c +++ b/sound/atmel/ac97c.c @@ -944,7 +944,7 @@ static int atmel_ac97c_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "no peripheral clock\n"); return PTR_ERR(pclk); } - clk_enable(pclk); + clk_prepare_enable(pclk); retval = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, THIS_MODULE, @@ -1122,7 +1122,7 @@ err_ioremap: err_request_irq: snd_card_free(card); err_snd_card_new: - clk_disable(pclk); + clk_disable_unprepare(pclk); clk_put(pclk); return retval; } @@ -1139,7 +1139,7 @@ static int atmel_ac97c_suspend(struct device *pdev) if (test_bit(DMA_TX_READY, &chip->flags)) dw_dma_cyclic_stop(chip->dma.tx_chan); } - clk_disable(chip->pclk); + clk_disable_unprepare(chip->pclk); return 0; } @@ -1149,7 +1149,7 @@ static int atmel_ac97c_resume(struct device *pdev) struct snd_card *card = dev_get_drvdata(pdev); struct atmel_ac97c *chip = card->private_data; - clk_enable(chip->pclk); + clk_prepare_enable(chip->pclk); if (cpu_is_at32ap7000()) { if (test_bit(DMA_RX_READY, &chip->flags)) dw_dma_cyclic_start(chip->dma.rx_chan); @@ -1177,7 +1177,7 @@ static int atmel_ac97c_remove(struct platform_device *pdev) ac97c_writel(chip, COMR, 0); ac97c_writel(chip, MR, 0); - clk_disable(chip->pclk); + clk_disable_unprepare(chip->pclk); clk_put(chip->pclk); iounmap(chip->regs); free_irq(chip->irq, chip); -- cgit v1.2.3 From 048184540171672a724ab8f8bada7fcc0762f5c6 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Fri, 5 Dec 2014 20:10:07 +0100 Subject: ALSA: atmel_abdac: Add missing clock prepare Clocks must be prepared before enabling them. Do this in one step. Replace clk_enable with clk_prepare_enable and clk_disable with clk_disable_unprepare. Signed-off-by: Alexander Stein Signed-off-by: Takashi Iwai --- sound/atmel/abdac.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/atmel/abdac.c b/sound/atmel/abdac.c index 31061e3521d4..023140504104 100644 --- a/sound/atmel/abdac.c +++ b/sound/atmel/abdac.c @@ -242,7 +242,7 @@ static int atmel_abdac_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */ case SNDRV_PCM_TRIGGER_RESUME: /* fall through */ case SNDRV_PCM_TRIGGER_START: - clk_enable(dac->sample_clk); + clk_prepare_enable(dac->sample_clk); retval = dw_dma_cyclic_start(dac->dma.chan); if (retval) goto out; @@ -254,7 +254,7 @@ static int atmel_abdac_trigger(struct snd_pcm_substream *substream, int cmd) dw_dma_cyclic_stop(dac->dma.chan); dac_writel(dac, DATA, 0); dac_writel(dac, CTRL, 0); - clk_disable(dac->sample_clk); + clk_disable_unprepare(dac->sample_clk); break; default: retval = -EINVAL; @@ -429,7 +429,7 @@ static int atmel_abdac_probe(struct platform_device *pdev) retval = PTR_ERR(sample_clk); goto out_put_pclk; } - clk_enable(pclk); + clk_prepare_enable(pclk); retval = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, THIS_MODULE, @@ -528,7 +528,7 @@ out_free_card: snd_card_free(card); out_put_sample_clk: clk_put(sample_clk); - clk_disable(pclk); + clk_disable_unprepare(pclk); out_put_pclk: clk_put(pclk); return retval; @@ -541,8 +541,8 @@ static int atmel_abdac_suspend(struct device *pdev) struct atmel_abdac *dac = card->private_data; dw_dma_cyclic_stop(dac->dma.chan); - clk_disable(dac->sample_clk); - clk_disable(dac->pclk); + clk_disable_unprepare(dac->sample_clk); + clk_disable_unprepare(dac->pclk); return 0; } @@ -552,8 +552,8 @@ static int atmel_abdac_resume(struct device *pdev) struct snd_card *card = dev_get_drvdata(pdev); struct atmel_abdac *dac = card->private_data; - clk_enable(dac->pclk); - clk_enable(dac->sample_clk); + clk_prepare_enable(dac->pclk); + clk_prepare_enable(dac->sample_clk); if (test_bit(DMA_READY, &dac->flags)) dw_dma_cyclic_start(dac->dma.chan); @@ -572,7 +572,7 @@ static int atmel_abdac_remove(struct platform_device *pdev) struct atmel_abdac *dac = get_dac(card); clk_put(dac->sample_clk); - clk_disable(dac->pclk); + clk_disable_unprepare(dac->pclk); clk_put(dac->pclk); dma_release_channel(dac->dma.chan); -- cgit v1.2.3