source: mainline/uspace/drv/audio/sb16/mixer.c@ 0ea8f83

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 0ea8f83 was a68e5e2, checked in by Jan Vesely <jano.vesely@…>, 14 years ago

sb16: Minor mixer changes.

  • Property mode set to 100644
File size: 9.6 KB
Line 
1/*
2 * Copyright (c) 2011 Jan Vesely
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <bool.h>
30#include <errno.h>
31#include <libarch/ddi.h>
32
33#include "ddf_log.h"
34#include "mixer.h"
35
36typedef struct channel {
37 uint8_t address;
38 unsigned shift;
39 unsigned volume_levels;
40 bool preserve_bits;
41} channel_t;
42
43typedef struct volume_item {
44 const char *description;
45 uint8_t channels;
46 const channel_t *channel_table;
47} volume_item_t;
48
49/* CT1335 channels */
50static const channel_t channels_table_ct1335[] = {
51 { 0x02, 1, 8, false }, /* Master, Mono, 3bit volume level */
52 { 0x06, 1, 8, false }, /* Midi, Mono, 3bit volume level */
53 { 0x08, 1, 8, false }, /* CD, Mono, 3bit volume level */
54 { 0x0a, 1, 4, false }, /* Voice, Mono, 2bit volume level */
55};
56
57/* CT1345 channels */
58static const channel_t channels_table_ct1345[] = {
59 { 0x22, 5, 8, true }, /* Master, Left, 3bit volume level */
60 { 0x22, 1, 8, true }, /* Master, Right, 3bit volume level */
61 { 0x26, 5, 8, true }, /* Midi, Left, 3bit volume level */
62 { 0x26, 1, 8, true }, /* Midi, Right, 3bit volume level */
63 { 0x28, 5, 8, true }, /* CD, Left, 3bit volume level */
64 { 0x28, 1, 8, true }, /* CD, Right, 3bit volume level */
65 { 0x2e, 5, 8, true }, /* Line, Left, 3bit volume level */
66 { 0x2e, 1, 8, true }, /* Line, Right, 3bit volume level */
67 { 0x04, 5, 8, true }, /* Voice, Left, 3bit volume level */
68 { 0x04, 1, 8, true }, /* Voice, Right, 3bit volume level */
69 { 0x0a, 1, 4, false }, /* Mic, Mono, 2bit volume level */
70};
71
72/* CT1745 channels */
73static const channel_t channels_table_ct1745[] = {
74 { 0x30, 3, 32, false }, /* Master, Left, 5bit volume level */
75 { 0x31, 3, 32, false }, /* Master, Right, 5bit volume level */
76 { 0x32, 3, 32, false }, /* Voice, Left, 5bit volume level */
77 { 0x33, 3, 32, false }, /* Voice, Right, 5bit volume level */
78 { 0x34, 3, 32, false }, /* MIDI, Left, 5bit volume level */
79 { 0x35, 3, 32, false }, /* MIDI, Right, 5bit volume level */
80 { 0x36, 3, 32, false }, /* CD, Left, 5bit volume level */
81 { 0x37, 3, 32, false }, /* CD, Right, 5bit volume level */
82 { 0x38, 3, 32, false }, /* Line, Left, 5bit volume level */
83 { 0x39, 3, 32, false }, /* Line, Right, 5bit volume level */
84 { 0x3a, 3, 32, false }, /* Mic, Mono, 5bit volume level */
85 { 0x3b, 6, 4, false }, /* PC speaker, Mono, 2bit volume level */
86 { 0x3f, 6, 4, false }, /* Input Gain, Left, 2bit volume level */
87 { 0x40, 6, 4, false }, /* Input Gain, Right, 2bit volume level */
88 { 0x41, 6, 4, false }, /* Output Gain, Left, 2bit volume level */
89 { 0x42, 6, 4, false }, /* Output Gain, Right, 2bit volume level */
90 { 0x44, 4, 16, false }, /* Treble, Left, 4bit volume level */
91 { 0x45, 4, 16, false }, /* Treble, Right, 4bit volume level */
92 { 0x46, 4, 16, false }, /* Bass, Left, 4bit volume level */
93 { 0x47, 4, 16, false }, /* Bass, Right, 4bit volume level */
94};
95
96static const volume_item_t volume_ct1335[] = {
97 { "Master", 1, &channels_table_ct1335[0] },
98 { "MIDI", 1, &channels_table_ct1335[1] },
99 { "CD", 1, &channels_table_ct1335[2] },
100 { "Voice", 1, &channels_table_ct1335[3] },
101};
102
103static const volume_item_t volume_ct1345[] = {
104 { "Master", 2, &channels_table_ct1345[0] },
105 { "Voice", 2, &channels_table_ct1345[8] },
106 { "Mic", 1, &channels_table_ct1345[10] },
107 { "MIDI", 2, &channels_table_ct1345[2] },
108 { "CD", 2, &channels_table_ct1345[4] },
109 { "Line", 2, &channels_table_ct1345[6] },
110};
111
112static const volume_item_t volume_ct1745[] = {
113 { "Master", 2, &channels_table_ct1745[0] },
114 { "Voice", 2, &channels_table_ct1745[2] },
115 { "MIDI", 2, &channels_table_ct1745[4] },
116 { "CD", 2, &channels_table_ct1745[6] },
117 { "Line", 2, &channels_table_ct1745[8] },
118 { "Mic", 1, &channels_table_ct1745[10] },
119 { "PC Speaker", 1, &channels_table_ct1745[11] },
120 { "Input Gain", 2, &channels_table_ct1745[12] },
121 { "Output Gain", 2, &channels_table_ct1745[14] },
122 { "Treble", 2, &channels_table_ct1745[16] },
123 { "Bass", 2, &channels_table_ct1745[0] },
124};
125
126static const struct {
127 size_t count;
128 const volume_item_t *table;
129} volume_table[] = {
130 [SB_MIXER_NONE] = { 0, NULL },
131 [SB_MIXER_UNKNOWN] = { 0, NULL },
132 [SB_MIXER_CT1335] = {
133 sizeof(volume_ct1335) / sizeof(volume_item_t), volume_ct1335 },
134 [SB_MIXER_CT1345] = {
135 sizeof(volume_ct1345) / sizeof(volume_item_t), volume_ct1345 },
136 [SB_MIXER_CT1745] = {
137 sizeof(volume_ct1745) / sizeof(volume_item_t), volume_ct1745 },
138};
139
140static void sb_mixer_max_master_levels(sb_mixer_t *mixer)
141{
142 assert(mixer);
143 /* Set Master to maximum */
144 if (!sb_mixer_get_control_item_count(mixer))
145 return;
146 const unsigned item = 0; /* 0 is Master. */
147 unsigned levels = 0, channels = 0, level;
148 const char *name = NULL;
149
150 sb_mixer_get_control_item_info(mixer, item, &name, &channels, &levels);
151 for (unsigned channel = 0; channel < channels; ++channel) {
152 level = sb_mixer_get_volume_level(mixer, item, channel);
153 ddf_log_note("Setting %s channel %d to %d (%d).\n",
154 name, channel, levels - 1, level);
155
156 sb_mixer_set_volume_level(mixer, item, channel, levels - 1);
157
158 level = sb_mixer_get_volume_level(mixer, item, channel);
159 ddf_log_note("%s channel %d set to %d.\n",
160 name, channel, level);
161 }
162}
163/*----------------------------------------------------------------------------*/
164const char * sb_mixer_type_str(sb_mixer_type_t type)
165{
166 static const char * names[] = {
167 [SB_MIXER_CT1335] = "CT 1335",
168 [SB_MIXER_CT1345] = "CT 1345",
169 [SB_MIXER_CT1745] = "CT 1745",
170 [SB_MIXER_UNKNOWN] = "Unknown mixer",
171 };
172 return names[type];
173}
174/*----------------------------------------------------------------------------*/
175int sb_mixer_init(sb_mixer_t *mixer, sb16_regs_t *regs, sb_mixer_type_t type)
176{
177 assert(mixer);
178 mixer->regs = regs;
179 mixer->type = type;
180 if (type == SB_MIXER_UNKNOWN)
181 return ENOTSUP;
182
183 if (type != SB_MIXER_NONE) {
184 pio_write_8(&regs->mixer_address, MIXER_RESET_ADDRESS);
185 pio_write_8(&regs->mixer_data, 1);
186 sb_mixer_max_master_levels(mixer);
187 }
188 pio_write_8(&regs->mixer_address, MIXER_PNP_IRQ_ADDRESS);
189 const uint8_t irq = pio_read_8(&regs->mixer_data);
190 pio_write_8(&regs->mixer_address, MIXER_PNP_DMA_ADDRESS);
191 const uint8_t dma = pio_read_8(&regs->mixer_data);
192 ddf_log_debug("SB16 setup with IRQ 0x%hhx and DMA 0x%hhx.\n", irq, dma);
193 return EOK;
194}
195/*----------------------------------------------------------------------------*/
196int sb_mixer_get_control_item_count(const sb_mixer_t *mixer)
197{
198 assert(mixer);
199 return volume_table[mixer->type].count;
200}
201/*----------------------------------------------------------------------------*/
202int sb_mixer_get_control_item_info(const sb_mixer_t *mixer, unsigned index,
203 const char** name, unsigned *channels, unsigned *levels)
204{
205 assert(mixer);
206 if (index > volume_table[mixer->type].count)
207 return ENOENT;
208
209 const volume_item_t item = volume_table[mixer->type].table[index];
210 if (name)
211 *name = item.description;
212 if (channels)
213 *channels = item.channels;
214 if (levels)
215 *levels = item.channel_table[0].volume_levels;
216 return EOK;
217}
218/*----------------------------------------------------------------------------*/
219int sb_mixer_set_volume_level(const sb_mixer_t *mixer,
220 unsigned index, unsigned channel, unsigned level)
221{
222 if (mixer->type == SB_MIXER_UNKNOWN || mixer->type == SB_MIXER_NONE)
223 return ENOTSUP;
224 if (index >= volume_table[mixer->type].count)
225 return ENOENT;
226 if (channel >= volume_table[mixer->type].table[index].channels)
227 return ENOENT;
228 const channel_t chan =
229 volume_table[mixer->type].table[index].channel_table[channel];
230
231 if (level > chan.volume_levels)
232 level = chan.volume_levels;
233
234 pio_write_8(&mixer->regs->mixer_address, chan.address);
235 uint8_t value = 0;
236
237 if (chan.preserve_bits) {
238 value = pio_read_8(&mixer->regs->mixer_data);
239 value &= ~(uint8_t)((chan.volume_levels - 1) << chan.shift);
240 }
241
242 value |= level << chan.shift;
243 pio_write_8(&mixer->regs->mixer_data, value);
244 return EOK;
245}
246/*----------------------------------------------------------------------------*/
247unsigned sb_mixer_get_volume_level(const sb_mixer_t *mixer, unsigned index,
248 unsigned channel)
249{
250 assert(mixer);
251 if (mixer->type == SB_MIXER_UNKNOWN
252 || mixer->type == SB_MIXER_NONE
253 || (index >= volume_table[mixer->type].count)
254 || (channel >= volume_table[mixer->type].table[index].channels))
255 return 0;
256
257 const channel_t chan =
258 volume_table[mixer->type].table[index].channel_table[channel];
259 pio_write_8(&mixer->regs->mixer_address, chan.address);
260 return (pio_read_8(&mixer->regs->mixer_data) >> chan.shift)
261 & (chan.volume_levels - 1);
262}
Note: See TracBrowser for help on using the repository browser.