harmony.c revision 5e246b850df563224be26f1d409cf66fd6c968df
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Hewlett-Packard Harmony audio driver 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is a driver for the Harmony audio chipset found 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * on the LASI ASIC of various early HP PA-RISC workstations. 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2004, Kyle McMartin <kyle@{debian.org,parisc-linux.org}> 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Based on the previous Harmony incarnations by, 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright 2000 (c) Linuxcare Canada, Alex deVries 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright 2000-2003 (c) Helge Deller 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright 2001 (c) Matthieu Delahaye 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright 2001 (c) Jean-Christophe Vaugeois 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright 2003 (c) Laurent Canet 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright 2004 (c) Stuart Brady 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License, version 2, as 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * published by the Free Software Foundation. 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License for more details. 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Notes: 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - graveyard and silence buffers last for lifetime of 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the driver. playback and capture buffers are allocated 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * per _open()/_close(). 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * TODO: 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/time.h> 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/wait.h> 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h> 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/dma-mapping.h> 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <sound/core.h> 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <sound/pcm.h> 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <sound/control.h> 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <sound/rawmidi.h> 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <sound/initval.h> 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <sound/info.h> 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/hardware.h> 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/parisc-device.h> 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "harmony.h" 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6103f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi Iwaistatic int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ 6203f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi Iwaistatic char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ 6303f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi Iwaimodule_param(index, int, 0444); 6403f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi IwaiMODULE_PARM_DESC(index, "Index value for Harmony driver."); 6503f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi Iwaimodule_param(id, charp, 0444); 6603f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi IwaiMODULE_PARM_DESC(id, "ID string for Harmony driver."); 6703f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi Iwai 6803f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi Iwai 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct parisc_device_id snd_harmony_devtable[] = { 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* bushmaster / flounder */ 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007A }, 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 712 / 715 */ 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007B }, 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* pace */ 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007E }, 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* outfield / coral II */ 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007F }, 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 0, } 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE(parisc, snd_harmony_devtable); 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NAME "harmony" 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PFX NAME ": " 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int snd_harmony_rates[] = { 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5512, 6615, 8000, 9600, 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11025, 16000, 18900, 22050, 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27428, 32000, 33075, 37800, 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44100, 48000 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int rate_bits[14] = { 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HARMONY_SR_5KHZ, HARMONY_SR_6KHZ, HARMONY_SR_8KHZ, 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HARMONY_SR_9KHZ, HARMONY_SR_11KHZ, HARMONY_SR_16KHZ, 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HARMONY_SR_18KHZ, HARMONY_SR_22KHZ, HARMONY_SR_27KHZ, 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HARMONY_SR_32KHZ, HARMONY_SR_33KHZ, HARMONY_SR_37KHZ, 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HARMONY_SR_44KHZ, HARMONY_SR_48KHZ 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10167b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaistatic struct snd_pcm_hw_constraint_list hw_constraint_rates = { 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .count = ARRAY_SIZE(snd_harmony_rates), 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .list = snd_harmony_rates, 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .mask = 0, 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10767b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaistatic inline unsigned long 10867b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaiharmony_read(struct snd_harmony *h, unsigned r) 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return __raw_readl(h->iobase + r); 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11367b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaistatic inline void 11467b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaiharmony_write(struct snd_harmony *h, unsigned r, unsigned long v) 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __raw_writel(v, h->iobase + r); 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11967b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaistatic inline void 12067b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaiharmony_wait_for_control(struct snd_harmony *h) 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (harmony_read(h, HARMONY_CNTL) & HARMONY_CNTL_C) ; 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12567b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaistatic inline void 12667b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaiharmony_reset(struct snd_harmony *h) 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_write(h, HARMONY_RESET, 1); 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mdelay(50); 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_write(h, HARMONY_RESET, 0); 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 13467b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaiharmony_disable_interrupts(struct snd_harmony *h) 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 dstatus; 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_wait_for_control(h); 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dstatus = harmony_read(h, HARMONY_DSTATUS); 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dstatus &= ~HARMONY_DSTATUS_IE; 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_write(h, HARMONY_DSTATUS, dstatus); 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 14467b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaiharmony_enable_interrupts(struct snd_harmony *h) 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 dstatus; 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_wait_for_control(h); 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dstatus = harmony_read(h, HARMONY_DSTATUS); 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dstatus |= HARMONY_DSTATUS_IE; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_write(h, HARMONY_DSTATUS, dstatus); 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 15467b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaiharmony_mute(struct snd_harmony *h) 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&h->mixer_lock, flags); 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_wait_for_control(h); 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_write(h, HARMONY_GAINCTL, HARMONY_GAIN_SILENCE); 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&h->mixer_lock, flags); 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 16567b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaiharmony_unmute(struct snd_harmony *h) 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&h->mixer_lock, flags); 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_wait_for_control(h); 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_write(h, HARMONY_GAINCTL, h->st.gain); 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&h->mixer_lock, flags); 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 17667b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaiharmony_set_control(struct snd_harmony *h) 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 ctrl; 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&h->lock, flags); 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ctrl = (HARMONY_CNTL_C | 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (h->st.format << 6) | 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (h->st.stereo << 5) | 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (h->st.rate)); 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_wait_for_control(h); 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_write(h, HARMONY_CNTL, ctrl); 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&h->lock, flags); 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic irqreturn_t 1957d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellssnd_harmony_interrupt(int irq, void *dev) 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 dstatus; 19867b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_harmony *h = dev; 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&h->lock); 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_disable_interrupts(h); 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_wait_for_control(h); 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dstatus = harmony_read(h, HARMONY_DSTATUS); 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&h->lock); 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dstatus & HARMONY_DSTATUS_PN) { 2073a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady if (h->psubs && h->st.playing) { 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&h->lock); 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->pbuf.buf += h->pbuf.count; /* PAGE_SIZE */ 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->pbuf.buf %= h->pbuf.size; /* MAX_BUFS*PAGE_SIZE */ 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_write(h, HARMONY_PNXTADD, 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->pbuf.addr + h->pbuf.buf); 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->stats.play_intr++; 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&h->lock); 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds snd_pcm_period_elapsed(h->psubs); 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&h->lock); 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_write(h, HARMONY_PNXTADD, h->sdma.addr); 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->stats.silence_intr++; 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&h->lock); 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dstatus & HARMONY_DSTATUS_RN) { 2263a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady if (h->csubs && h->st.capturing) { 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&h->lock); 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->cbuf.buf += h->cbuf.count; 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->cbuf.buf %= h->cbuf.size; 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_write(h, HARMONY_RNXTADD, 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->cbuf.addr + h->cbuf.buf); 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->stats.rec_intr++; 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&h->lock); 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds snd_pcm_period_elapsed(h->csubs); 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&h->lock); 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_write(h, HARMONY_RNXTADD, h->gdma.addr); 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->stats.graveyard_intr++; 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&h->lock); 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&h->lock); 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_enable_interrupts(h); 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&h->lock); 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssnd_harmony_rate_bits(int rate) 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int i; 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ARRAY_SIZE(snd_harmony_rates); i++) 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (snd_harmony_rates[i] == rate) 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rate_bits[i]; 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return HARMONY_SR_44KHZ; 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26367b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaistatic struct snd_pcm_hardware snd_harmony_playback = 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SNDRV_PCM_INFO_JOINT_DUPLEX | SNDRV_PCM_INFO_MMAP_VALID | 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SNDRV_PCM_INFO_BLOCK_TRANSFER), 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .formats = (SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_MU_LAW | 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SNDRV_PCM_FMTBIT_A_LAW), 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .rates = (SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_48000 | 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SNDRV_PCM_RATE_KNOT), 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .rate_min = 5512, 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .rate_max = 48000, 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .channels_min = 1, 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .channels_max = 2, 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .buffer_bytes_max = MAX_BUF_SIZE, 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .period_bytes_min = BUF_SIZE, 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .period_bytes_max = BUF_SIZE, 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .periods_min = 1, 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .periods_max = MAX_BUFS, 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .fifo_size = 0, 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28467b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaistatic struct snd_pcm_hardware snd_harmony_capture = 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SNDRV_PCM_INFO_JOINT_DUPLEX | SNDRV_PCM_INFO_MMAP_VALID | 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SNDRV_PCM_INFO_BLOCK_TRANSFER), 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .formats = (SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_MU_LAW | 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SNDRV_PCM_FMTBIT_A_LAW), 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .rates = (SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_48000 | 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SNDRV_PCM_RATE_KNOT), 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .rate_min = 5512, 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .rate_max = 48000, 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .channels_min = 1, 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .channels_max = 2, 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .buffer_bytes_max = MAX_BUF_SIZE, 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .period_bytes_min = BUF_SIZE, 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .period_bytes_max = BUF_SIZE, 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .periods_min = 1, 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .periods_max = MAX_BUFS, 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .fifo_size = 0, 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 30667b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaisnd_harmony_playback_trigger(struct snd_pcm_substream *ss, int cmd) 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 30867b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_harmony *h = snd_pcm_substream_chip(ss); 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (h->st.capturing) 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31303f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi Iwai spin_lock(&h->lock); 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SNDRV_PCM_TRIGGER_START: 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->st.playing = 1; 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_write(h, HARMONY_PNXTADD, h->pbuf.addr); 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_write(h, HARMONY_RNXTADD, h->gdma.addr); 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_unmute(h); 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_enable_interrupts(h); 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SNDRV_PCM_TRIGGER_STOP: 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->st.playing = 0; 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_mute(h); 3253a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady harmony_write(h, HARMONY_PNXTADD, h->sdma.addr); 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_disable_interrupts(h); 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SNDRV_PCM_TRIGGER_SUSPEND: 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 33203f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi Iwai spin_unlock(&h->lock); 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds snd_BUG(); 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 33603f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi Iwai spin_unlock(&h->lock); 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 34267b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaisnd_harmony_capture_trigger(struct snd_pcm_substream *ss, int cmd) 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 34467b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_harmony *h = snd_pcm_substream_chip(ss); 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (h->st.playing) 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34903f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi Iwai spin_lock(&h->lock); 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SNDRV_PCM_TRIGGER_START: 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->st.capturing = 1; 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_write(h, HARMONY_PNXTADD, h->sdma.addr); 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_write(h, HARMONY_RNXTADD, h->cbuf.addr); 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_unmute(h); 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_enable_interrupts(h); 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SNDRV_PCM_TRIGGER_STOP: 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->st.capturing = 0; 3603a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady harmony_mute(h); 3613a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady harmony_write(h, HARMONY_RNXTADD, h->gdma.addr); 3623a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady harmony_disable_interrupts(h); 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SNDRV_PCM_TRIGGER_SUSPEND: 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 36803f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi Iwai spin_unlock(&h->lock); 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds snd_BUG(); 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 37203f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi Iwai spin_unlock(&h->lock); 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 37867b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaisnd_harmony_set_data_format(struct snd_harmony *h, int fmt, int force) 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int o = h->st.format; 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int n; 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch(fmt) { 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SNDRV_PCM_FORMAT_S16_BE: 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds n = HARMONY_DF_16BIT_LINEAR; 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SNDRV_PCM_FORMAT_A_LAW: 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds n = HARMONY_DF_8BIT_ALAW; 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SNDRV_PCM_FORMAT_MU_LAW: 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds n = HARMONY_DF_8BIT_ULAW; 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds n = HARMONY_DF_16BIT_LINEAR; 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (force || o != n) { 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds snd_pcm_format_set_silence(fmt, h->sdma.area, SILENCE_BUFSZ / 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (snd_pcm_format_physical_width(fmt) 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds / 8)); 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return n; 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 40867b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaisnd_harmony_playback_prepare(struct snd_pcm_substream *ss) 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 41067b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_harmony *h = snd_pcm_substream_chip(ss); 41167b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_pcm_runtime *rt = ss->runtime; 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (h->st.capturing) 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->pbuf.size = snd_pcm_lib_buffer_bytes(ss); 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->pbuf.count = snd_pcm_lib_period_bytes(ss); 4183a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady if (h->pbuf.buf >= h->pbuf.size) 4193a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady h->pbuf.buf = 0; 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->st.playing = 0; 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->st.rate = snd_harmony_rate_bits(rt->rate); 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->st.format = snd_harmony_set_data_format(h, rt->format, 0); 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rt->channels == 2) 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->st.stereo = HARMONY_SS_STEREO; 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->st.stereo = HARMONY_SS_MONO; 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_set_control(h); 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->pbuf.addr = rt->dma_addr; 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 43867b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaisnd_harmony_capture_prepare(struct snd_pcm_substream *ss) 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 44067b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_harmony *h = snd_pcm_substream_chip(ss); 44167b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_pcm_runtime *rt = ss->runtime; 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (h->st.playing) 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->cbuf.size = snd_pcm_lib_buffer_bytes(ss); 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->cbuf.count = snd_pcm_lib_period_bytes(ss); 4483a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady if (h->cbuf.buf >= h->cbuf.size) 4493a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady h->cbuf.buf = 0; 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->st.capturing = 0; 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->st.rate = snd_harmony_rate_bits(rt->rate); 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->st.format = snd_harmony_set_data_format(h, rt->format, 0); 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rt->channels == 2) 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->st.stereo = HARMONY_SS_STEREO; 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->st.stereo = HARMONY_SS_MONO; 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_set_control(h); 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->cbuf.addr = rt->dma_addr; 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic snd_pcm_uframes_t 46867b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaisnd_harmony_playback_pointer(struct snd_pcm_substream *ss) 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 47067b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_pcm_runtime *rt = ss->runtime; 47167b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_harmony *h = snd_pcm_substream_chip(ss); 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long pcuradd; 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long played; 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(h->st.playing) || (h->psubs == NULL)) 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((h->pbuf.addr == 0) || (h->pbuf.size == 0)) 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcuradd = harmony_read(h, HARMONY_PCURADD); 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds played = pcuradd - h->pbuf.addr; 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef HARMONY_DEBUG 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG PFX "playback_pointer is 0x%lx-0x%lx = %d bytes\n", 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcuradd, h->pbuf.addr, played); 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pcuradd > h->pbuf.addr + h->pbuf.size) { 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return bytes_to_frames(rt, played); 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic snd_pcm_uframes_t 49767b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaisnd_harmony_capture_pointer(struct snd_pcm_substream *ss) 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 49967b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_pcm_runtime *rt = ss->runtime; 50067b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_harmony *h = snd_pcm_substream_chip(ss); 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long rcuradd; 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long caught; 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(h->st.capturing) || (h->csubs == NULL)) 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((h->cbuf.addr == 0) || (h->cbuf.size == 0)) 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rcuradd = harmony_read(h, HARMONY_RCURADD); 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds caught = rcuradd - h->cbuf.addr; 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef HARMONY_DEBUG 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG PFX "capture_pointer is 0x%lx-0x%lx = %d bytes\n", 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rcuradd, h->cbuf.addr, caught); 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rcuradd > h->cbuf.addr + h->cbuf.size) { 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return bytes_to_frames(rt, caught); 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 52667b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaisnd_harmony_playback_open(struct snd_pcm_substream *ss) 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 52867b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_harmony *h = snd_pcm_substream_chip(ss); 52967b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_pcm_runtime *rt = ss->runtime; 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->psubs = ss; 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rt->hw = snd_harmony_playback; 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds snd_pcm_hw_constraint_list(rt, 0, SNDRV_PCM_HW_PARAM_RATE, 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &hw_constraint_rates); 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = snd_pcm_hw_constraint_integer(rt, SNDRV_PCM_HW_PARAM_PERIODS); 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err < 0) 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 54567b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaisnd_harmony_capture_open(struct snd_pcm_substream *ss) 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 54767b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_harmony *h = snd_pcm_substream_chip(ss); 54867b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_pcm_runtime *rt = ss->runtime; 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->csubs = ss; 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rt->hw = snd_harmony_capture; 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds snd_pcm_hw_constraint_list(rt, 0, SNDRV_PCM_HW_PARAM_RATE, 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &hw_constraint_rates); 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = snd_pcm_hw_constraint_integer(rt, SNDRV_PCM_HW_PARAM_PERIODS); 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err < 0) 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 56467b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaisnd_harmony_playback_close(struct snd_pcm_substream *ss) 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 56667b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_harmony *h = snd_pcm_substream_chip(ss); 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->psubs = NULL; 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 57267b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaisnd_harmony_capture_close(struct snd_pcm_substream *ss) 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 57467b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_harmony *h = snd_pcm_substream_chip(ss); 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->csubs = NULL; 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 58067b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaisnd_harmony_hw_params(struct snd_pcm_substream *ss, 58167b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_pcm_hw_params *hw) 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 58467b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_harmony *h = snd_pcm_substream_chip(ss); 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = snd_pcm_lib_malloc_pages(ss, params_buffer_bytes(hw)); 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err > 0 && h->dma.type == SNDRV_DMA_TYPE_CONTINUOUS) 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ss->runtime->dma_addr = __pa(ss->runtime->dma_area); 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 59467b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaisnd_harmony_hw_free(struct snd_pcm_substream *ss) 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return snd_pcm_lib_free_pages(ss); 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 59967b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaistatic struct snd_pcm_ops snd_harmony_playback_ops = { 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = snd_harmony_playback_open, 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .close = snd_harmony_playback_close, 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .ioctl = snd_pcm_lib_ioctl, 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .hw_params = snd_harmony_hw_params, 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .hw_free = snd_harmony_hw_free, 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .prepare = snd_harmony_playback_prepare, 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .trigger = snd_harmony_playback_trigger, 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .pointer = snd_harmony_playback_pointer, 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 61067b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaistatic struct snd_pcm_ops snd_harmony_capture_ops = { 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = snd_harmony_capture_open, 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .close = snd_harmony_capture_close, 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .ioctl = snd_pcm_lib_ioctl, 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .hw_params = snd_harmony_hw_params, 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .hw_free = snd_harmony_hw_free, 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .prepare = snd_harmony_capture_prepare, 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .trigger = snd_harmony_capture_trigger, 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .pointer = snd_harmony_capture_pointer, 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 62267b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaisnd_harmony_pcm_init(struct snd_harmony *h) 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 62467b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_pcm *pcm; 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_disable_interrupts(h); 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = snd_pcm_new(h->card, "harmony", 0, 1, 1, &pcm); 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err < 0) 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &snd_harmony_playback_ops); 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &snd_harmony_capture_ops); 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcm->private_data = h; 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcm->info_flags = 0; 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcpy(pcm->name, "harmony"); 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->pcm = pcm; 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->psubs = NULL; 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->csubs = NULL; 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* initialize graveyard buffer */ 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->dma.type = SNDRV_DMA_TYPE_DEV; 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->dma.dev = &h->dev->dev; 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = snd_dma_alloc_pages(h->dma.type, 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->dma.dev, 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUF_SIZE*GRAVEYARD_BUFS, 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &h->gdma); 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err < 0) { 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR PFX "cannot allocate graveyard buffer!\n"); 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* initialize silence buffers */ 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = snd_dma_alloc_pages(h->dma.type, 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->dma.dev, 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUF_SIZE*SILENCE_BUFS, 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &h->sdma); 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err < 0) { 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR PFX "cannot allocate silence buffer!\n"); 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* pre-allocate space for DMA */ 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = snd_pcm_lib_preallocate_pages_for_all(pcm, h->dma.type, 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->dma.dev, 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MAX_BUF_SIZE, 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MAX_BUF_SIZE); 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err < 0) { 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR PFX "buffer allocation error: %d\n", err); 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->st.format = snd_harmony_set_data_format(h, 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SNDRV_PCM_FORMAT_S16_BE, 1); 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 68567b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaisnd_harmony_set_new_gain(struct snd_harmony *h) 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_wait_for_control(h); 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_write(h, HARMONY_GAINCTL, h->st.gain); 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 69267b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaisnd_harmony_mixercontrol_info(struct snd_kcontrol *kc, 69367b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_ctl_elem_info *uinfo) 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int mask = (kc->private_value >> 16) & 0xff; 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int left_shift = (kc->private_value) & 0xff; 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int right_shift = (kc->private_value >> 8) & 0xff; 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SNDRV_CTL_ELEM_TYPE_INTEGER; 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uinfo->count = left_shift == right_shift ? 1 : 2; 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uinfo->value.integer.min = 0; 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uinfo->value.integer.max = mask; 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 70967b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaisnd_harmony_volume_get(struct snd_kcontrol *kc, 71067b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_ctl_elem_value *ucontrol) 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 71267b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_harmony *h = snd_kcontrol_chip(kc); 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int shift_left = (kc->private_value) & 0xff; 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int shift_right = (kc->private_value >> 8) & 0xff; 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int mask = (kc->private_value >> 16) & 0xff; 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int invert = (kc->private_value >> 24) & 0xff; 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int left, right; 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 71903f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi Iwai spin_lock_irq(&h->mixer_lock); 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds left = (h->st.gain >> shift_left) & mask; 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds right = (h->st.gain >> shift_right) & mask; 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (invert) { 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds left = mask - left; 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds right = mask - right; 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7273a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ucontrol->value.integer.value[0] = left; 7293a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady if (shift_left != shift_right) 7303a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady ucontrol->value.integer.value[1] = right; 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 73203f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi Iwai spin_unlock_irq(&h->mixer_lock); 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 73867b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaisnd_harmony_volume_put(struct snd_kcontrol *kc, 73967b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_ctl_elem_value *ucontrol) 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 74167b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_harmony *h = snd_kcontrol_chip(kc); 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int shift_left = (kc->private_value) & 0xff; 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int shift_right = (kc->private_value >> 8) & 0xff; 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int mask = (kc->private_value >> 16) & 0xff; 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int invert = (kc->private_value >> 24) & 0xff; 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int left, right; 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int old_gain = h->st.gain; 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 74903f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi Iwai spin_lock_irq(&h->mixer_lock); 7503a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds left = ucontrol->value.integer.value[0] & mask; 7523a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady if (invert) 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds left = mask - left; 7543a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady h->st.gain &= ~( (mask << shift_left ) ); 7553a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady h->st.gain |= (left << shift_left); 7563a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady 7573a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady if (shift_left != shift_right) { 7583a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady right = ucontrol->value.integer.value[1] & mask; 7593a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady if (invert) 7603a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady right = mask - right; 7613a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady h->st.gain &= ~( (mask << shift_right) ); 7623a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady h->st.gain |= (right << shift_right); 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7643a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady 7653a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady snd_harmony_set_new_gain(h); 7663a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady 76703f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi Iwai spin_unlock_irq(&h->mixer_lock); 7683a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady 7693a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady return h->st.gain != old_gain; 7703a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady} 7713a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady 7723a165680168758733b7a9f7fb835954fbe6b91a8Stuart Bradystatic int 77367b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaisnd_harmony_captureroute_info(struct snd_kcontrol *kc, 77467b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_ctl_elem_info *uinfo) 7753a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady{ 7763a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady static char *texts[2] = { "Line", "Mic" }; 7773a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 7783a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady uinfo->count = 1; 7793a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady uinfo->value.enumerated.items = 2; 7803a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady if (uinfo->value.enumerated.item > 1) 7813a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady uinfo->value.enumerated.item = 1; 7823a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady strcpy(uinfo->value.enumerated.name, 7833a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady texts[uinfo->value.enumerated.item]); 7843a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady return 0; 7853a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady} 7863a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady 7873a165680168758733b7a9f7fb835954fbe6b91a8Stuart Bradystatic int 78867b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaisnd_harmony_captureroute_get(struct snd_kcontrol *kc, 78967b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_ctl_elem_value *ucontrol) 7903a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady{ 79167b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_harmony *h = snd_kcontrol_chip(kc); 7923a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady int value; 7933a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady 79403f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi Iwai spin_lock_irq(&h->mixer_lock); 7953a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady 7963a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady value = (h->st.gain >> HARMONY_GAIN_IS_SHIFT) & 1; 7973a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady ucontrol->value.enumerated.item[0] = value; 7983a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady 79903f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi Iwai spin_unlock_irq(&h->mixer_lock); 8003a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady 8013a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady return 0; 8023a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady} 8033a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady 8043a165680168758733b7a9f7fb835954fbe6b91a8Stuart Bradystatic int 80567b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaisnd_harmony_captureroute_put(struct snd_kcontrol *kc, 80667b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_ctl_elem_value *ucontrol) 8073a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady{ 80867b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_harmony *h = snd_kcontrol_chip(kc); 8093a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady int value; 8103a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady int old_gain = h->st.gain; 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 81203f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi Iwai spin_lock_irq(&h->mixer_lock); 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8143a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady value = ucontrol->value.enumerated.item[0] & 1; 8153a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady h->st.gain &= ~HARMONY_GAIN_IS_MASK; 8163a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady h->st.gain |= value << HARMONY_GAIN_IS_SHIFT; 8173a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds snd_harmony_set_new_gain(h); 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 82003f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi Iwai spin_unlock_irq(&h->mixer_lock); 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8223a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady return h->st.gain != old_gain; 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 82567b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai#define HARMONY_CONTROLS ARRAY_SIZE(snd_harmony_controls) 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define HARMONY_VOLUME(xname, left_shift, right_shift, mask, invert) \ 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .info = snd_harmony_mixercontrol_info, \ 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .get = snd_harmony_volume_get, .put = snd_harmony_volume_put, \ 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .private_value = ((left_shift) | ((right_shift) << 8) | \ 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((mask) << 16) | ((invert) << 24)) } 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 83467b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaistatic struct snd_kcontrol_new snd_harmony_controls[] = { 8353a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady HARMONY_VOLUME("Master Playback Volume", HARMONY_GAIN_LO_SHIFT, 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HARMONY_GAIN_RO_SHIFT, HARMONY_GAIN_OUT, 1), 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HARMONY_VOLUME("Capture Volume", HARMONY_GAIN_LI_SHIFT, 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HARMONY_GAIN_RI_SHIFT, HARMONY_GAIN_IN, 0), 8393a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady HARMONY_VOLUME("Monitor Volume", HARMONY_GAIN_MA_SHIFT, 8403a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady HARMONY_GAIN_MA_SHIFT, HARMONY_GAIN_MA, 1), 8413a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady { 8423a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 8433a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady .name = "Input Route", 8443a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady .info = snd_harmony_captureroute_info, 8453a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady .get = snd_harmony_captureroute_get, 8463a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady .put = snd_harmony_captureroute_put 8473a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady }, 8483a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady HARMONY_VOLUME("Internal Speaker Switch", HARMONY_GAIN_SE_SHIFT, 8493a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady HARMONY_GAIN_SE_SHIFT, 1, 0), 8503a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady HARMONY_VOLUME("Line-Out Switch", HARMONY_GAIN_LE_SHIFT, 8513a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady HARMONY_GAIN_LE_SHIFT, 1, 0), 8523a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady HARMONY_VOLUME("Headphones Switch", HARMONY_GAIN_HE_SHIFT, 8533a165680168758733b7a9f7fb835954fbe6b91a8Stuart Brady HARMONY_GAIN_HE_SHIFT, 1, 0), 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 856992378a06413116c6a7cf2ad597e096589e531aaHelge Dellerstatic void __devinit 85767b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaisnd_harmony_mixer_reset(struct snd_harmony *h) 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_mute(h); 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_reset(h); 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->st.gain = HARMONY_GAIN_DEFAULT; 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds harmony_unmute(h); 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 865992378a06413116c6a7cf2ad597e096589e531aaHelge Dellerstatic int __devinit 86667b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaisnd_harmony_mixer_init(struct snd_harmony *h) 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 86867b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_card *card = h->card; 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int idx, err; 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8715e246b850df563224be26f1d409cf66fd6c968dfTakashi Iwai if (snd_BUG_ON(!h)) 8725e246b850df563224be26f1d409cf66fd6c968dfTakashi Iwai reutrn -EINVAL; 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcpy(card->mixername, "Harmony Gain control interface"); 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (idx = 0; idx < HARMONY_CONTROLS; idx++) { 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = snd_ctl_add(card, 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds snd_ctl_new1(&snd_harmony_controls[idx], h)); 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err < 0) 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds snd_harmony_mixer_reset(h); 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 88867b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaisnd_harmony_free(struct snd_harmony *h) 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (h->gdma.addr) 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds snd_dma_free_pages(&h->gdma); 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (h->sdma.addr) 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds snd_dma_free_pages(&h->sdma); 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (h->irq >= 0) 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(h->irq, h); 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (h->iobase) 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iounmap(h->iobase); 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parisc_set_drvdata(h->dev, NULL); 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(h); 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 90867b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaisnd_harmony_dev_free(struct snd_device *dev) 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 91067b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_harmony *h = dev->device_data; 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return snd_harmony_free(h); 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __devinit 91567b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwaisnd_harmony_create(struct snd_card *card, 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct parisc_device *padev, 91767b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_harmony **rchip) 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 92067b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_harmony *h; 92167b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai static struct snd_device_ops ops = { 9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .dev_free = snd_harmony_dev_free, 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }; 9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *rchip = NULL; 9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 92703f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi Iwai h = kzalloc(sizeof(*h), GFP_KERNEL); 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (h == NULL) 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 93153f01bba49938f115237fe43a261c31ac13ae5c6Matthew Wilcox h->hpa = padev->hpa.start; 9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->card = card; 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h->dev = padev; 93403f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi Iwai h->irq = -1; 93553f01bba49938f115237fe43a261c31ac13ae5c6Matthew Wilcox h->iobase = ioremap_nocache(padev->hpa.start, HARMONY_SIZE); 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (h->iobase == NULL) { 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR PFX "unable to remap hpa 0x%lx\n", 93853f01bba49938f115237fe43a261c31ac13ae5c6Matthew Wilcox padev->hpa.start); 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EBUSY; 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto free_and_ret; 9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 94303f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi Iwai err = request_irq(padev->irq, snd_harmony_interrupt, 0, 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "harmony", h); 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) { 9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR PFX "could not obtain interrupt %d", 94703f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi Iwai padev->irq); 9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto free_and_ret; 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 95003f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi Iwai h->irq = padev->irq; 9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&h->mixer_lock); 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&h->lock); 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h, &ops)) < 0) { 9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto free_and_ret; 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 960a76af199dc025e8f5cf6b9542efadc3de5163a7aTakashi Iwai snd_card_set_dev(card, &padev->dev); 961a76af199dc025e8f5cf6b9542efadc3de5163a7aTakashi Iwai 9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *rchip = h; 9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfree_and_ret: 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds snd_harmony_free(h); 9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __devinit 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssnd_harmony_probe(struct parisc_device *padev) 9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 97567b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_card *card; 97667b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai struct snd_harmony *h; 9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds card = snd_card_new(index, id, THIS_MODULE, 0); 9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (card == NULL) 9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = snd_harmony_create(card, padev, &h); 98303f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi Iwai if (err < 0) 9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto free_and_ret; 9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = snd_harmony_pcm_init(h); 98703f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi Iwai if (err < 0) 9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto free_and_ret; 9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = snd_harmony_mixer_init(h); 99103f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi Iwai if (err < 0) 9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto free_and_ret; 9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcpy(card->driver, "harmony"); 9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcpy(card->shortname, "Harmony"); 9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sprintf(card->longname, "%s at 0x%lx, irq %i", 9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds card->shortname, h->hpa, h->irq); 9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = snd_card_register(card); 100003f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi Iwai if (err < 0) 10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto free_and_ret; 10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 100303f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi Iwai parisc_set_drvdata(padev, card); 10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfree_and_ret: 10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds snd_card_free(card); 10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __devexit 10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssnd_harmony_remove(struct parisc_device *padev) 10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 101403f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi Iwai snd_card_free(parisc_get_drvdata(padev)); 101503f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi Iwai parisc_set_drvdata(padev, NULL); 10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct parisc_driver snd_harmony_driver = { 10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "harmony", 10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = snd_harmony_devtable, 10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = snd_harmony_probe, 10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .remove = snd_harmony_remove, 10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init 10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsalsa_harmony_init(void) 10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 102903f9ae2505cf2f5d56c197b4045ed9dba5ce8912Takashi Iwai return register_parisc_driver(&snd_harmony_driver); 10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit 10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsalsa_harmony_fini(void) 10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 103567b1020d88a77a73bd9ccbc21733c155a4d7d44cTakashi Iwai unregister_parisc_driver(&snd_harmony_driver); 10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Kyle McMartin <kyle@parisc-linux.org>"); 10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Harmony sound driver"); 10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(alsa_harmony_init); 10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(alsa_harmony_fini); 1044