aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/ali5451
diff options
context:
space:
mode:
authorSasha Khapyorsky <sashak@smlink.com>2005-05-30 02:09:56 -0400
committerJaroslav Kysela <perex@suse.cz>2005-06-22 06:27:27 -0400
commit5cbff89cbc1087870c32ecb0b7f1965f93ec5401 (patch)
tree856eb77cee5507fe11407bd79ee398a9fbfff924 /sound/pci/ali5451
parent299676b1d792ca643f37ff4f3275694a841739b7 (diff)
[ALSA] Modem support for ALI5451
ALI5451 driver This patch adds modem support for ali5451. Since it is same pci device all is done in ali5451.c. Signed-off-by: Sasha Khapyorsky <sashak@smlink.com> Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Diffstat (limited to 'sound/pci/ali5451')
-rw-r--r--sound/pci/ali5451/ali5451.c281
1 files changed, 218 insertions, 63 deletions
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c
index 038f56ad42f1..eb5c36d31a52 100644
--- a/sound/pci/ali5451/ali5451.c
+++ b/sound/pci/ali5451/ali5451.c
@@ -98,6 +98,8 @@ MODULE_PARM_DESC(spdif, "Support SPDIF I/O");
98#define ALI_LEF_CHANNEL 23 98#define ALI_LEF_CHANNEL 23
99#define ALI_SURR_LEFT_CHANNEL 26 99#define ALI_SURR_LEFT_CHANNEL 26
100#define ALI_SURR_RIGHT_CHANNEL 25 100#define ALI_SURR_RIGHT_CHANNEL 25
101#define ALI_MODEM_IN_CHANNEL 21
102#define ALI_MODEM_OUT_CHANNEL 20
101 103
102#define SNDRV_ALI_VOICE_TYPE_PCM 01 104#define SNDRV_ALI_VOICE_TYPE_PCM 01
103#define SNDRV_ALI_VOICE_TYPE_OTH 02 105#define SNDRV_ALI_VOICE_TYPE_OTH 02
@@ -122,7 +124,15 @@ MODULE_PARM_DESC(spdif, "Support SPDIF I/O");
122 124
123#define ALI_SCTRL 0x48 125#define ALI_SCTRL 0x48
124#define ALI_SPDIF_OUT_ENABLE 0x20 126#define ALI_SPDIF_OUT_ENABLE 0x20
127#define ALI_SCTRL_LINE_IN2 (1 << 9)
128#define ALI_SCTRL_GPIO_IN2 (1 << 13)
129#define ALI_SCTRL_LINE_OUT_EN (1 << 20)
130#define ALI_SCTRL_GPIO_OUT_EN (1 << 23)
131#define ALI_SCTRL_CODEC1_READY (1 << 24)
132#define ALI_SCTRL_CODEC2_READY (1 << 25)
125#define ALI_AC97_GPIO 0x4c 133#define ALI_AC97_GPIO 0x4c
134#define ALI_AC97_GPIO_ENABLE 0x8000
135#define ALI_AC97_GPIO_DATA_SHIFT 16
126#define ALI_SPDIF_CS 0x70 136#define ALI_SPDIF_CS 0x70
127#define ALI_SPDIF_CTRL 0x74 137#define ALI_SPDIF_CTRL 0x74
128#define ALI_SPDIF_IN_FUNC_ENABLE 0x02 138#define ALI_SPDIF_IN_FUNC_ENABLE 0x02
@@ -143,6 +153,7 @@ MODULE_PARM_DESC(spdif, "Support SPDIF I/O");
143 #define TARGET_REACHED 0x00008000 153 #define TARGET_REACHED 0x00008000
144 #define MIXER_OVERFLOW 0x00000800 154 #define MIXER_OVERFLOW 0x00000800
145 #define MIXER_UNDERFLOW 0x00000400 155 #define MIXER_UNDERFLOW 0x00000400
156 #define GPIO_IRQ 0x01000000
146#define ALI_SBBL_SBCL 0xc0 157#define ALI_SBBL_SBCL 0xc0
147#define ALI_SBCTRL_SBE2R_SBDD 0xc4 158#define ALI_SBCTRL_SBE2R_SBDD 0xc4
148#define ALI_STIMER 0xc8 159#define ALI_STIMER 0xc8
@@ -162,6 +173,9 @@ MODULE_PARM_DESC(spdif, "Support SPDIF I/O");
162 173
163#define ALI_REG(codec, x) ((codec)->port + x) 174#define ALI_REG(codec, x) ((codec)->port + x)
164 175
176#define MAX_CODECS 2
177
178
165typedef struct snd_stru_ali ali_t; 179typedef struct snd_stru_ali ali_t;
166typedef struct snd_ali_stru_voice snd_ali_voice_t; 180typedef struct snd_ali_stru_voice snd_ali_voice_t;
167 181
@@ -245,7 +259,7 @@ struct snd_stru_ali {
245 struct pci_dev *pci_m7101; 259 struct pci_dev *pci_m7101;
246 260
247 snd_card_t *card; 261 snd_card_t *card;
248 snd_pcm_t *pcm; 262 snd_pcm_t *pcm[MAX_CODECS];
249 alidev_t synth; 263 alidev_t synth;
250 snd_ali_channel_control_t chregs; 264 snd_ali_channel_control_t chregs;
251 265
@@ -255,8 +269,10 @@ struct snd_stru_ali {
255 unsigned int spurious_irq_count; 269 unsigned int spurious_irq_count;
256 unsigned int spurious_irq_max_delta; 270 unsigned int spurious_irq_max_delta;
257 271
272 unsigned int num_of_codecs;
273
258 ac97_bus_t *ac97_bus; 274 ac97_bus_t *ac97_bus;
259 ac97_t *ac97; 275 ac97_t *ac97[MAX_CODECS];
260 unsigned short ac97_ext_id; 276 unsigned short ac97_ext_id;
261 unsigned short ac97_ext_status; 277 unsigned short ac97_ext_status;
262 278
@@ -489,7 +505,12 @@ static void snd_ali_codec_write(ac97_t *ac97,
489 ali_t *codec = ac97->private_data; 505 ali_t *codec = ac97->private_data;
490 506
491 snd_ali_printk("codec_write: reg=%xh data=%xh.\n", reg, val); 507 snd_ali_printk("codec_write: reg=%xh data=%xh.\n", reg, val);
492 snd_ali_codec_poke(codec, 0, reg, val); 508 if(reg == AC97_GPIO_STATUS) {
509 outl((val << ALI_AC97_GPIO_DATA_SHIFT)|ALI_AC97_GPIO_ENABLE,
510 ALI_REG(codec, ALI_AC97_GPIO));
511 return;
512 }
513 snd_ali_codec_poke(codec, ac97->num, reg, val);
493 return ; 514 return ;
494} 515}
495 516
@@ -499,7 +520,7 @@ static unsigned short snd_ali_codec_read(ac97_t *ac97, unsigned short reg)
499 ali_t *codec = ac97->private_data; 520 ali_t *codec = ac97->private_data;
500 521
501 snd_ali_printk("codec_read reg=%xh.\n", reg); 522 snd_ali_printk("codec_read reg=%xh.\n", reg);
502 return (snd_ali_codec_peek(codec, 0, reg)); 523 return (snd_ali_codec_peek(codec, ac97->num, reg));
503} 524}
504 525
505/* 526/*
@@ -1051,7 +1072,7 @@ static irqreturn_t snd_ali_card_interrupt(int irq,
1051} 1072}
1052 1073
1053 1074
1054static snd_ali_voice_t *snd_ali_alloc_voice(ali_t * codec, int type, int rec) 1075static snd_ali_voice_t *snd_ali_alloc_voice(ali_t * codec, int type, int rec, int channel)
1055{ 1076{
1056 snd_ali_voice_t *pvoice = NULL; 1077 snd_ali_voice_t *pvoice = NULL;
1057 unsigned long flags; 1078 unsigned long flags;
@@ -1061,7 +1082,8 @@ static snd_ali_voice_t *snd_ali_alloc_voice(ali_t * codec, int type, int rec)
1061 1082
1062 spin_lock_irqsave(&codec->voice_alloc, flags); 1083 spin_lock_irqsave(&codec->voice_alloc, flags);
1063 if (type == SNDRV_ALI_VOICE_TYPE_PCM) { 1084 if (type == SNDRV_ALI_VOICE_TYPE_PCM) {
1064 idx = snd_ali_find_free_channel(codec,rec); 1085 idx = channel > 0 ? snd_ali_alloc_pcm_channel(codec, channel) :
1086 snd_ali_find_free_channel(codec,rec);
1065 if(idx < 0) { 1087 if(idx < 0) {
1066 snd_printk("ali_alloc_voice: err.\n"); 1088 snd_printk("ali_alloc_voice: err.\n");
1067 spin_unlock_irqrestore(&codec->voice_alloc, flags); 1089 spin_unlock_irqrestore(&codec->voice_alloc, flags);
@@ -1297,7 +1319,7 @@ static int snd_ali_playback_hw_params(snd_pcm_substream_t * substream,
1297 1319
1298 if (params_buffer_size(hw_params)/2 != params_period_size(hw_params)) { 1320 if (params_buffer_size(hw_params)/2 != params_period_size(hw_params)) {
1299 if (evoice == NULL) { 1321 if (evoice == NULL) {
1300 evoice = snd_ali_alloc_voice(codec, SNDRV_ALI_VOICE_TYPE_PCM, 0); 1322 evoice = snd_ali_alloc_voice(codec, SNDRV_ALI_VOICE_TYPE_PCM, 0, -1);
1301 if (evoice == NULL) 1323 if (evoice == NULL)
1302 return -ENOMEM; 1324 return -ENOMEM;
1303 pvoice->extra = evoice; 1325 pvoice->extra = evoice;
@@ -1328,13 +1350,13 @@ static int snd_ali_playback_hw_free(snd_pcm_substream_t * substream)
1328 return 0; 1350 return 0;
1329} 1351}
1330 1352
1331static int snd_ali_capture_hw_params(snd_pcm_substream_t * substream, 1353static int snd_ali_hw_params(snd_pcm_substream_t * substream,
1332 snd_pcm_hw_params_t * hw_params) 1354 snd_pcm_hw_params_t * hw_params)
1333{ 1355{
1334 return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); 1356 return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
1335} 1357}
1336 1358
1337static int snd_ali_capture_hw_free(snd_pcm_substream_t * substream) 1359static int snd_ali_hw_free(snd_pcm_substream_t * substream)
1338{ 1360{
1339 return snd_pcm_lib_free_pages(substream); 1361 return snd_pcm_lib_free_pages(substream);
1340} 1362}
@@ -1428,7 +1450,7 @@ static int snd_ali_playback_prepare(snd_pcm_substream_t * substream)
1428} 1450}
1429 1451
1430 1452
1431static int snd_ali_capture_prepare(snd_pcm_substream_t * substream) 1453static int snd_ali_prepare(snd_pcm_substream_t * substream)
1432{ 1454{
1433 ali_t *codec = snd_pcm_substream_chip(substream); 1455 ali_t *codec = snd_pcm_substream_chip(substream);
1434 snd_pcm_runtime_t *runtime = substream->runtime; 1456 snd_pcm_runtime_t *runtime = substream->runtime;
@@ -1446,11 +1468,13 @@ static int snd_ali_capture_prepare(snd_pcm_substream_t * substream)
1446 1468
1447 spin_lock_irqsave(&codec->reg_lock, flags); 1469 spin_lock_irqsave(&codec->reg_lock, flags);
1448 1470
1449 snd_ali_printk("capture_prepare...\n"); 1471 snd_ali_printk("ali_prepare...\n");
1450 1472
1451 snd_ali_enable_special_channel(codec,pvoice->number); 1473 snd_ali_enable_special_channel(codec,pvoice->number);
1452 1474
1453 Delta = snd_ali_convert_rate(runtime->rate, 1); 1475 Delta = (pvoice->number == ALI_MODEM_IN_CHANNEL ||
1476 pvoice->number == ALI_MODEM_OUT_CHANNEL) ?
1477 0x1000 : snd_ali_convert_rate(runtime->rate, pvoice->mode);
1454 1478
1455 // Prepare capture intr channel 1479 // Prepare capture intr channel
1456 if (pvoice->number == ALI_SPDIF_IN_CHANNEL) { 1480 if (pvoice->number == ALI_SPDIF_IN_CHANNEL) {
@@ -1534,7 +1558,7 @@ static snd_pcm_uframes_t snd_ali_playback_pointer(snd_pcm_substream_t *substream
1534} 1558}
1535 1559
1536 1560
1537static snd_pcm_uframes_t snd_ali_capture_pointer(snd_pcm_substream_t *substream) 1561static snd_pcm_uframes_t snd_ali_pointer(snd_pcm_substream_t *substream)
1538{ 1562{
1539 ali_t *codec = snd_pcm_substream_chip(substream); 1563 ali_t *codec = snd_pcm_substream_chip(substream);
1540 snd_pcm_runtime_t *runtime = substream->runtime; 1564 snd_pcm_runtime_t *runtime = substream->runtime;
@@ -1616,7 +1640,8 @@ static void snd_ali_pcm_free_substream(snd_pcm_runtime_t *runtime)
1616 } 1640 }
1617} 1641}
1618 1642
1619static int snd_ali_playback_open(snd_pcm_substream_t * substream) 1643static int snd_ali_open(snd_pcm_substream_t * substream, int rec, int channel,
1644 snd_pcm_hardware_t *phw)
1620{ 1645{
1621 ali_t *codec = snd_pcm_substream_chip(substream); 1646 ali_t *codec = snd_pcm_substream_chip(substream);
1622 snd_pcm_runtime_t *runtime = substream->runtime; 1647 snd_pcm_runtime_t *runtime = substream->runtime;
@@ -1624,7 +1649,7 @@ static int snd_ali_playback_open(snd_pcm_substream_t * substream)
1624 unsigned long flags = 0; 1649 unsigned long flags = 0;
1625 1650
1626 spin_lock_irqsave(&codec->reg_lock, flags); 1651 spin_lock_irqsave(&codec->reg_lock, flags);
1627 pvoice = snd_ali_alloc_voice(codec, SNDRV_ALI_VOICE_TYPE_PCM, 0); 1652 pvoice = snd_ali_alloc_voice(codec, SNDRV_ALI_VOICE_TYPE_PCM, rec, channel);
1628 if (pvoice == NULL) { 1653 if (pvoice == NULL) {
1629 spin_unlock_irqrestore(&codec->reg_lock, flags); 1654 spin_unlock_irqrestore(&codec->reg_lock, flags);
1630 return -EAGAIN; 1655 return -EAGAIN;
@@ -1636,49 +1661,31 @@ static int snd_ali_playback_open(snd_pcm_substream_t * substream)
1636 runtime->private_data = pvoice; 1661 runtime->private_data = pvoice;
1637 runtime->private_free = snd_ali_pcm_free_substream; 1662 runtime->private_free = snd_ali_pcm_free_substream;
1638 1663
1639 runtime->hw = snd_ali_playback; 1664 runtime->hw = *phw;
1640 snd_pcm_set_sync(substream); 1665 snd_pcm_set_sync(substream);
1641 snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 64*1024); 1666 snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 64*1024);
1642 return 0; 1667 return 0;
1643} 1668}
1644 1669
1670static int snd_ali_playback_open(snd_pcm_substream_t * substream)
1671{
1672 return snd_ali_open(substream, 0, -1, &snd_ali_playback);
1673}
1645 1674
1646static int snd_ali_capture_open(snd_pcm_substream_t * substream) 1675static int snd_ali_capture_open(snd_pcm_substream_t * substream)
1647{ 1676{
1648 ali_t *codec = snd_pcm_substream_chip(substream); 1677 return snd_ali_open(substream, 1, -1, &snd_ali_capture);
1649 snd_pcm_runtime_t *runtime = substream->runtime;
1650 snd_ali_voice_t *pvoice;
1651 unsigned long flags;
1652
1653 spin_lock_irqsave(&codec->reg_lock, flags);
1654 pvoice = snd_ali_alloc_voice(codec, SNDRV_ALI_VOICE_TYPE_PCM, 1);
1655 if (pvoice == NULL) {
1656 spin_unlock_irqrestore(&codec->reg_lock, flags);
1657 return -EAGAIN;
1658 }
1659 pvoice->codec = codec;
1660 spin_unlock_irqrestore(&codec->reg_lock, flags);
1661
1662 pvoice->substream = substream;
1663 runtime->private_data = pvoice;
1664 runtime->private_free = snd_ali_pcm_free_substream;
1665 runtime->hw = snd_ali_capture;
1666 snd_pcm_set_sync(substream);
1667 snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 64*1024);
1668 return 0;
1669} 1678}
1670 1679
1671
1672static int snd_ali_playback_close(snd_pcm_substream_t * substream) 1680static int snd_ali_playback_close(snd_pcm_substream_t * substream)
1673{ 1681{
1674 return 0; 1682 return 0;
1675} 1683}
1676 1684
1677static int snd_ali_capture_close(snd_pcm_substream_t * substream) 1685static int snd_ali_close(snd_pcm_substream_t * substream)
1678{ 1686{
1679 ali_t *codec = snd_pcm_substream_chip(substream); 1687 ali_t *codec = snd_pcm_substream_chip(substream);
1680 snd_pcm_runtime_t *runtime = substream->runtime; 1688 snd_ali_voice_t *pvoice = (snd_ali_voice_t *) substream->runtime->private_data;
1681 snd_ali_voice_t *pvoice = (snd_ali_voice_t *) runtime->private_data;
1682 1689
1683 snd_ali_disable_special_channel(codec,pvoice->number); 1690 snd_ali_disable_special_channel(codec,pvoice->number);
1684 1691
@@ -1698,29 +1705,121 @@ static snd_pcm_ops_t snd_ali_playback_ops = {
1698 1705
1699static snd_pcm_ops_t snd_ali_capture_ops = { 1706static snd_pcm_ops_t snd_ali_capture_ops = {
1700 .open = snd_ali_capture_open, 1707 .open = snd_ali_capture_open,
1701 .close = snd_ali_capture_close, 1708 .close = snd_ali_close,
1702 .ioctl = snd_ali_ioctl, 1709 .ioctl = snd_ali_ioctl,
1703 .hw_params = snd_ali_capture_hw_params, 1710 .hw_params = snd_ali_hw_params,
1704 .hw_free = snd_ali_capture_hw_free, 1711 .hw_free = snd_ali_hw_free,
1705 .prepare = snd_ali_capture_prepare, 1712 .prepare = snd_ali_prepare,
1713 .trigger = snd_ali_trigger,
1714 .pointer = snd_ali_pointer,
1715};
1716
1717/*
1718 * Modem PCM
1719 */
1720
1721static int snd_ali_modem_hw_params(snd_pcm_substream_t * substream,
1722 snd_pcm_hw_params_t * hw_params)
1723{
1724 ali_t *chip = snd_pcm_substream_chip(substream);
1725 unsigned int modem_num = chip->num_of_codecs - 1;
1726 snd_ac97_write(chip->ac97[modem_num], AC97_LINE1_RATE, params_rate(hw_params));
1727 snd_ac97_write(chip->ac97[modem_num], AC97_LINE1_LEVEL, 0);
1728 return snd_ali_hw_params(substream, hw_params);
1729}
1730
1731static snd_pcm_hardware_t snd_ali_modem =
1732{
1733 .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
1734 SNDRV_PCM_INFO_BLOCK_TRANSFER |
1735 SNDRV_PCM_INFO_MMAP_VALID |
1736 SNDRV_PCM_INFO_RESUME |
1737 SNDRV_PCM_INFO_SYNC_START),
1738 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1739 .rates = SNDRV_PCM_RATE_KNOT|SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000,
1740 .rate_min = 8000,
1741 .rate_max = 16000,
1742 .channels_min = 1,
1743 .channels_max = 1,
1744 .buffer_bytes_max = (256*1024),
1745 .period_bytes_min = 64,
1746 .period_bytes_max = (256*1024),
1747 .periods_min = 1,
1748 .periods_max = 1024,
1749 .fifo_size = 0,
1750};
1751
1752static int snd_ali_modem_open(snd_pcm_substream_t * substream, int rec, int channel)
1753{
1754 static unsigned int rates [] = {8000,9600,12000,16000};
1755 static snd_pcm_hw_constraint_list_t hw_constraint_rates = {
1756 .count = ARRAY_SIZE(rates),
1757 .list = rates,
1758 .mask = 0,
1759 };
1760 int err = snd_ali_open(substream, rec, channel, &snd_ali_modem);
1761 if (err)
1762 return err;
1763 return snd_pcm_hw_constraint_list(substream->runtime, 0,
1764 SNDRV_PCM_HW_PARAM_RATE, &hw_constraint_rates);
1765}
1766
1767static int snd_ali_modem_playback_open(snd_pcm_substream_t * substream)
1768{
1769 return snd_ali_modem_open(substream, 0, ALI_MODEM_OUT_CHANNEL);
1770}
1771
1772static int snd_ali_modem_capture_open(snd_pcm_substream_t * substream)
1773{
1774 return snd_ali_modem_open(substream, 1, ALI_MODEM_IN_CHANNEL);
1775}
1776
1777static snd_pcm_ops_t snd_ali_modem_playback_ops = {
1778 .open = snd_ali_modem_playback_open,
1779 .close = snd_ali_close,
1780 .ioctl = snd_pcm_lib_ioctl,
1781 .hw_params = snd_ali_modem_hw_params,
1782 .hw_free = snd_ali_hw_free,
1783 .prepare = snd_ali_prepare,
1784 .trigger = snd_ali_trigger,
1785 .pointer = snd_ali_pointer,
1786};
1787
1788static snd_pcm_ops_t snd_ali_modem_capture_ops = {
1789 .open = snd_ali_modem_capture_open,
1790 .close = snd_ali_close,
1791 .ioctl = snd_pcm_lib_ioctl,
1792 .hw_params = snd_ali_modem_hw_params,
1793 .hw_free = snd_ali_hw_free,
1794 .prepare = snd_ali_prepare,
1706 .trigger = snd_ali_trigger, 1795 .trigger = snd_ali_trigger,
1707 .pointer = snd_ali_capture_pointer, 1796 .pointer = snd_ali_pointer,
1797};
1798
1799
1800struct ali_pcm_description {
1801 char *name;
1802 unsigned int playback_num;
1803 unsigned int capture_num;
1804 snd_pcm_ops_t *playback_ops;
1805 snd_pcm_ops_t *capture_ops;
1708}; 1806};
1709 1807
1710 1808
1711static void snd_ali_pcm_free(snd_pcm_t *pcm) 1809static void snd_ali_pcm_free(snd_pcm_t *pcm)
1712{ 1810{
1713 ali_t *codec = pcm->private_data; 1811 ali_t *codec = pcm->private_data;
1714 codec->pcm = NULL; 1812 codec->pcm[pcm->device] = NULL;
1715} 1813}
1716 1814
1717static int __devinit snd_ali_pcm(ali_t * codec, int device, snd_pcm_t ** rpcm) 1815
1816static int __devinit snd_ali_pcm(ali_t * codec, int device, struct ali_pcm_description *desc)
1718{ 1817{
1719 snd_pcm_t *pcm; 1818 snd_pcm_t *pcm;
1720 int err; 1819 int err;
1721 1820
1722 if (rpcm) *rpcm = NULL; 1821 err = snd_pcm_new(codec->card, desc->name, device,
1723 err = snd_pcm_new(codec->card, "ALI 5451", device, ALI_CHANNELS, 1, &pcm); 1822 desc->playback_num, desc->capture_num, &pcm);
1724 if (err < 0) { 1823 if (err < 0) {
1725 snd_printk("snd_ali_pcm: err called snd_pcm_new.\n"); 1824 snd_printk("snd_ali_pcm: err called snd_pcm_new.\n");
1726 return err; 1825 return err;
@@ -1728,20 +1827,36 @@ static int __devinit snd_ali_pcm(ali_t * codec, int device, snd_pcm_t ** rpcm)
1728 pcm->private_data = codec; 1827 pcm->private_data = codec;
1729 pcm->private_free = snd_ali_pcm_free; 1828 pcm->private_free = snd_ali_pcm_free;
1730 pcm->info_flags = 0; 1829 pcm->info_flags = 0;
1731 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ali_playback_ops); 1830 if (desc->playback_ops)
1732 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ali_capture_ops); 1831 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, desc->playback_ops);
1832 if (desc->capture_ops)
1833 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, desc->capture_ops);
1733 1834
1734 snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, 1835 snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
1735 snd_dma_pci_data(codec->pci), 64*1024, 128*1024); 1836 snd_dma_pci_data(codec->pci), 64*1024, 128*1024);
1736 1837
1737 pcm->info_flags = 0; 1838 pcm->info_flags = 0;
1738 pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; 1839 pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
1739 strcpy(pcm->name, "ALI 5451"); 1840 strcpy(pcm->name, desc->name);
1740 codec->pcm = pcm; 1841 codec->pcm[0] = pcm;
1741 if (rpcm) *rpcm = pcm;
1742 return 0; 1842 return 0;
1743} 1843}
1744 1844
1845struct ali_pcm_description ali_pcms[] = {
1846 { "ALI 5451", ALI_CHANNELS, 1, &snd_ali_playback_ops, &snd_ali_capture_ops },
1847 { "ALI 5451 modem", 1, 1, &snd_ali_modem_playback_ops, &snd_ali_modem_capture_ops }
1848};
1849
1850static int __devinit snd_ali_build_pcms(ali_t *codec)
1851{
1852 int i, err;
1853 for(i = 0 ; i < codec->num_of_codecs && i < ARRAY_SIZE(ali_pcms) ; i++)
1854 if((err = snd_ali_pcm(codec, i, &ali_pcms[i])) < 0)
1855 return err;
1856 return 0;
1857}
1858
1859
1745#define ALI5451_SPDIF(xname, xindex, value) \ 1860#define ALI5451_SPDIF(xname, xindex, value) \
1746{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\ 1861{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\
1747.info = snd_ali5451_spdif_info, .get = snd_ali5451_spdif_get, \ 1862.info = snd_ali5451_spdif_info, .get = snd_ali5451_spdif_get, \
@@ -1860,14 +1975,14 @@ static void snd_ali_mixer_free_ac97_bus(ac97_bus_t *bus)
1860static void snd_ali_mixer_free_ac97(ac97_t *ac97) 1975static void snd_ali_mixer_free_ac97(ac97_t *ac97)
1861{ 1976{
1862 ali_t *codec = ac97->private_data; 1977 ali_t *codec = ac97->private_data;
1863 codec->ac97 = NULL; 1978 codec->ac97[ac97->num] = NULL;
1864} 1979}
1865 1980
1866static int __devinit snd_ali_mixer(ali_t * codec) 1981static int __devinit snd_ali_mixer(ali_t * codec)
1867{ 1982{
1868 ac97_template_t ac97; 1983 ac97_template_t ac97;
1869 unsigned int idx; 1984 unsigned int idx;
1870 int err; 1985 int i, err;
1871 static ac97_bus_ops_t ops = { 1986 static ac97_bus_ops_t ops = {
1872 .write = snd_ali_codec_write, 1987 .write = snd_ali_codec_write,
1873 .read = snd_ali_codec_read, 1988 .read = snd_ali_codec_read,
@@ -1880,10 +1995,16 @@ static int __devinit snd_ali_mixer(ali_t * codec)
1880 memset(&ac97, 0, sizeof(ac97)); 1995 memset(&ac97, 0, sizeof(ac97));
1881 ac97.private_data = codec; 1996 ac97.private_data = codec;
1882 ac97.private_free = snd_ali_mixer_free_ac97; 1997 ac97.private_free = snd_ali_mixer_free_ac97;
1883 if ((err = snd_ac97_mixer(codec->ac97_bus, &ac97, &codec->ac97)) < 0) { 1998
1884 snd_printk("ali mixer creating error.\n"); 1999 for ( i = 0 ; i < codec->num_of_codecs ; i++) {
2000 ac97.num = i;
2001 if ((err = snd_ac97_mixer(codec->ac97_bus, &ac97, &codec->ac97[i])) < 0) {
2002 snd_printk("ali mixer %d creating error.\n", i);
2003 if(i == 0)
1885 return err; 2004 return err;
1886 } 2005 }
2006 }
2007
1887 if (codec->spdif_support) { 2008 if (codec->spdif_support) {
1888 for(idx = 0; idx < ARRAY_SIZE(snd_ali5451_mixer_spdif); idx++) { 2009 for(idx = 0; idx < ARRAY_SIZE(snd_ali5451_mixer_spdif); idx++) {
1889 err=snd_ctl_add(codec->card, snd_ctl_new1(&snd_ali5451_mixer_spdif[idx], codec)); 2010 err=snd_ctl_add(codec->card, snd_ctl_new1(&snd_ali5451_mixer_spdif[idx], codec));
@@ -1904,8 +2025,12 @@ static int ali_suspend(snd_card_t *card, pm_message_t state)
1904 if (! im) 2025 if (! im)
1905 return 0; 2026 return 0;
1906 2027
1907 snd_pcm_suspend_all(chip->pcm); 2028 for(i = 0 ; i < chip->num_of_codecs ; i++) {
1908 snd_ac97_suspend(chip->ac97); 2029 if (chip->pcm[i])
2030 snd_pcm_suspend_all(chip->pcm[i]);
2031 if(chip->ac97[i])
2032 snd_ac97_suspend(chip->ac97[i]);
2033 }
1909 2034
1910 spin_lock_irq(&chip->reg_lock); 2035 spin_lock_irq(&chip->reg_lock);
1911 2036
@@ -1969,7 +2094,9 @@ static int ali_resume(snd_card_t *card)
1969 2094
1970 spin_unlock_irq(&chip->reg_lock); 2095 spin_unlock_irq(&chip->reg_lock);
1971 2096
1972 snd_ac97_resume(chip->ac97); 2097 for(i = 0 ; i < chip->num_of_codecs ; i++)
2098 if(chip->ac97[i])
2099 snd_ac97_resume(chip->ac97[i]);
1973 2100
1974 return 0; 2101 return 0;
1975} 2102}
@@ -2036,11 +2163,37 @@ static int snd_ali_chip_init(ali_t *codec)
2036 codec->spdif_mask = 0x00000002; 2163 codec->spdif_mask = 0x00000002;
2037 } 2164 }
2038 2165
2166 codec->num_of_codecs = 1;
2167
2168 /* secondary codec - modem */
2169 if (inl(ALI_REG(codec, ALI_SCTRL)) & ALI_SCTRL_CODEC2_READY) {
2170 codec->num_of_codecs++;
2171 outl(inl(ALI_REG(codec, ALI_SCTRL)) |
2172 (ALI_SCTRL_LINE_IN2|ALI_SCTRL_GPIO_IN2|ALI_SCTRL_LINE_OUT_EN),
2173 ALI_REG(codec, ALI_SCTRL));
2174 }
2175
2039 snd_ali_printk("chip initialize succeed.\n"); 2176 snd_ali_printk("chip initialize succeed.\n");
2040 return 0; 2177 return 0;
2041 2178
2042} 2179}
2043 2180
2181/* proc for register dump */
2182static void snd_ali_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *buf)
2183{
2184 ali_t *codec = entry->private_data;
2185 int i;
2186 for(i = 0 ; i < 256 ; i+= 4)
2187 snd_iprintf(buf, "%02x: %08x\n", i, inl(ALI_REG(codec, i)));
2188}
2189
2190static void __devinit snd_ali_proc_init(ali_t *codec)
2191{
2192 snd_info_entry_t *entry;
2193 if(!snd_card_proc_new(codec->card, "ali5451", &entry))
2194 snd_info_set_text_ops(entry, codec, 1024, snd_ali_proc_read);
2195}
2196
2044static int __devinit snd_ali_resources(ali_t *codec) 2197static int __devinit snd_ali_resources(ali_t *codec)
2045{ 2198{
2046 int err; 2199 int err;
@@ -2233,11 +2386,13 @@ static int __devinit snd_ali_probe(struct pci_dev *pci,
2233 } 2386 }
2234 2387
2235 snd_ali_printk("pcm building ...\n"); 2388 snd_ali_printk("pcm building ...\n");
2236 if ((err = snd_ali_pcm(codec, 0, NULL)) < 0) { 2389 if ((err = snd_ali_build_pcms(codec)) < 0) {
2237 snd_card_free(card); 2390 snd_card_free(card);
2238 return err; 2391 return err;
2239 } 2392 }
2240 2393
2394 snd_ali_proc_init(codec);
2395
2241 strcpy(card->driver, "ALI5451"); 2396 strcpy(card->driver, "ALI5451");
2242 strcpy(card->shortname, "ALI 5451"); 2397 strcpy(card->shortname, "ALI 5451");
2243 2398