diff options
author | Sasha Khapyorsky <sashak@smlink.com> | 2005-05-30 02:09:56 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2005-06-22 06:27:27 -0400 |
commit | 5cbff89cbc1087870c32ecb0b7f1965f93ec5401 (patch) | |
tree | 856eb77cee5507fe11407bd79ee398a9fbfff924 | |
parent | 299676b1d792ca643f37ff4f3275694a841739b7 (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>
-rw-r--r-- | sound/pci/ali5451/ali5451.c | 281 |
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 | |||
165 | typedef struct snd_stru_ali ali_t; | 179 | typedef struct snd_stru_ali ali_t; |
166 | typedef struct snd_ali_stru_voice snd_ali_voice_t; | 180 | typedef 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 | ||
1054 | static snd_ali_voice_t *snd_ali_alloc_voice(ali_t * codec, int type, int rec) | 1075 | static 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 | ||
1331 | static int snd_ali_capture_hw_params(snd_pcm_substream_t * substream, | 1353 | static 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 | ||
1337 | static int snd_ali_capture_hw_free(snd_pcm_substream_t * substream) | 1359 | static 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 | ||
1431 | static int snd_ali_capture_prepare(snd_pcm_substream_t * substream) | 1453 | static 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 | ||
1537 | static snd_pcm_uframes_t snd_ali_capture_pointer(snd_pcm_substream_t *substream) | 1561 | static 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 | ||
1619 | static int snd_ali_playback_open(snd_pcm_substream_t * substream) | 1643 | static 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 | ||
1670 | static 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 | ||
1646 | static int snd_ali_capture_open(snd_pcm_substream_t * substream) | 1675 | static 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 | |||
1672 | static int snd_ali_playback_close(snd_pcm_substream_t * substream) | 1680 | static int snd_ali_playback_close(snd_pcm_substream_t * substream) |
1673 | { | 1681 | { |
1674 | return 0; | 1682 | return 0; |
1675 | } | 1683 | } |
1676 | 1684 | ||
1677 | static int snd_ali_capture_close(snd_pcm_substream_t * substream) | 1685 | static 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 | ||
1699 | static snd_pcm_ops_t snd_ali_capture_ops = { | 1706 | static 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 | |||
1721 | static 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 | |||
1731 | static 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 | |||
1752 | static 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 | |||
1767 | static 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 | |||
1772 | static 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 | |||
1777 | static 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 | |||
1788 | static 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 | |||
1800 | struct 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 | ||
1711 | static void snd_ali_pcm_free(snd_pcm_t *pcm) | 1809 | static 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 | ||
1717 | static int __devinit snd_ali_pcm(ali_t * codec, int device, snd_pcm_t ** rpcm) | 1815 | |
1816 | static 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 | ||
1845 | struct 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 | |||
1850 | static 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) | |||
1860 | static void snd_ali_mixer_free_ac97(ac97_t *ac97) | 1975 | static 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 | ||
1866 | static int __devinit snd_ali_mixer(ali_t * codec) | 1981 | static 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 */ | ||
2182 | static 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 | |||
2190 | static 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 | |||
2044 | static int __devinit snd_ali_resources(ali_t *codec) | 2197 | static 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 | ||