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

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

sb16: Use channel tables to simplify channel volume manipulation.

  • Property mode set to 100644
File size: 9.4 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
36#define CT_MIXER_RESET_ADDRESS 0x00
37
38typedef struct channel {
39 uint8_t address;
40 unsigned shift;
41 unsigned volume_levels;
42 bool preserve_bits;
43} channel_t;
44
45typedef struct volume_item {
46 const char *description;
47 uint8_t channels;
48 const channel_t *channel_table;
49} volume_item_t;
50
51/* CT1335 channels */
52static const channel_t channels_table_ct1335[] = {
53 { 0x02, 1, 8, false }, /* Master, Mono, 3bit volume level */
54 { 0x06, 1, 8, false }, /* Midi, Mono, 3bit volume level */
55 { 0x08, 1, 8, false }, /* CD, Mono, 3bit volume level */
56 { 0x0a, 1, 4, false }, /* Voice, Mono, 2bit volume level */
57};
58
59/* CT1345 channels */
60static const channel_t channels_table_ct1345[] = {
61 { 0x22, 5, 8, true }, /* Master, Left, 3bit volume level */
62 { 0x22, 1, 8, true }, /* Master, Right, 3bit volume level */
63 { 0x26, 5, 8, true }, /* Midi, Left, 3bit volume level */
64 { 0x26, 1, 8, true }, /* Midi, Right, 3bit volume level */
65 { 0x28, 5, 8, true }, /* CD, Left, 3bit volume level */
66 { 0x28, 1, 8, true }, /* CD, Right, 3bit volume level */
67 { 0x2e, 5, 8, true }, /* Line, Left, 3bit volume level */
68 { 0x2e, 1, 8, true }, /* Line, Right, 3bit volume level */
69 { 0x04, 5, 8, true }, /* Voice, Left, 3bit volume level */
70 { 0x04, 1, 8, true }, /* Voice, Right, 3bit volume level */
71 { 0x0a, 1, 4, false }, /* Mic, Mono, 2bit volume level */
72};
73
74/* CT1745 channels */
75static const channel_t channels_table_ct1745[] = {
76 { 0x30, 3, 32, false }, /* Master, Left, 5bit volume level */
77 { 0x31, 3, 32, false }, /* Master, Right, 5bit volume level */
78 { 0x32, 3, 32, false }, /* Voice, Left, 5bit volume level */
79 { 0x33, 3, 32, false }, /* Voice, Right, 5bit volume level */
80 { 0x34, 3, 32, false }, /* MIDI, Left, 5bit volume level */
81 { 0x35, 3, 32, false }, /* MIDI, Right, 5bit volume level */
82 { 0x36, 3, 32, false }, /* CD, Left, 5bit volume level */
83 { 0x37, 3, 32, false }, /* CD, Right, 5bit volume level */
84 { 0x38, 3, 32, false }, /* Line, Left, 5bit volume level */
85 { 0x39, 3, 32, false }, /* Line, Right, 5bit volume level */
86 { 0x3a, 3, 32, false }, /* Mic, Mono, 5bit volume level */
87 { 0x3b, 6, 4, false }, /* PC speaker, Mono, 2bit volume level */
88 { 0x3f, 6, 4, false }, /* Input Gain, Left, 2bit volume level */
89 { 0x40, 6, 4, false }, /* Input Gain, Right, 2bit volume level */
90 { 0x41, 6, 4, false }, /* Output Gain, Left, 2bit volume level */
91 { 0x42, 6, 4, false }, /* Output Gain, Right, 2bit volume level */
92 { 0x44, 4, 16, false }, /* Treble, Left, 4bit volume level */
93 { 0x45, 4, 16, false }, /* Treble, Right, 4bit volume level */
94 { 0x46, 4, 16, false }, /* Bass, Left, 4bit volume level */
95 { 0x47, 4, 16, false }, /* Bass, Right, 4bit volume level */
96};
97
98static const volume_item_t volume_ct1335[] = {
99 { "Master", 1, &channels_table_ct1335[0] },
100 { "MIDI", 1, &channels_table_ct1335[1] },
101 { "CD", 1, &channels_table_ct1335[2] },
102 { "Voice", 1, &channels_table_ct1335[3] },
103};
104
105static const volume_item_t volume_ct1345[] = {
106 { "Master", 2, &channels_table_ct1345[0] },
107 { "Voice", 2, &channels_table_ct1345[8] },
108 { "Mic", 1, &channels_table_ct1345[10] },
109 { "MIDI", 2, &channels_table_ct1345[2] },
110 { "CD", 2, &channels_table_ct1345[4] },
111 { "Line", 2, &channels_table_ct1345[6] },
112};
113
114static const volume_item_t volume_ct1745[] = {
115 { "Master", 2, &channels_table_ct1745[0] },
116 { "Voice", 2, &channels_table_ct1745[2] },
117 { "MIDI", 2, &channels_table_ct1745[4] },
118 { "CD", 2, &channels_table_ct1745[6] },
119 { "Line", 2, &channels_table_ct1745[8] },
120 { "Mic", 1, &channels_table_ct1745[10] },
121 { "PC Speaker", 1, &channels_table_ct1745[11] },
122 { "Input Gain", 2, &channels_table_ct1745[12] },
123 { "Output Gain", 2, &channels_table_ct1745[14] },
124 { "Treble", 2, &channels_table_ct1745[16] },
125 { "Bass", 2, &channels_table_ct1745[0] },
126};
127
128static const struct {
129 size_t count;
130 const volume_item_t *table;
131} volume_table[] = {
132 [SB_MIXER_NONE] = { 0, NULL },
133 [SB_MIXER_UNKNOWN] = { 0, NULL },
134 [SB_MIXER_CT1335] = {
135 sizeof(volume_ct1335) / sizeof(volume_item_t), volume_ct1335 },
136 [SB_MIXER_CT1345] = {
137 sizeof(volume_ct1345) / sizeof(volume_item_t), volume_ct1345 },
138 [SB_MIXER_CT1745] = {
139 sizeof(volume_ct1745) / sizeof(volume_item_t), volume_ct1745 },
140};
141
142static void sb_mixer_max_master_levels(sb_mixer_t *mixer)
143{
144 assert(mixer);
145 /* Set Master to maximum */
146 if (!sb_mixer_get_control_item_count(mixer))
147 return;
148 unsigned levels = 0, channels = 0, current_level;
149 const char *name = NULL;
150 sb_mixer_get_control_item_info(mixer, 0, &name, &channels, &levels);
151 unsigned channel = 0;
152 for (;channel < channels; ++channel) {
153 current_level =
154 sb_mixer_get_volume_level(mixer, 0, channel);
155 ddf_log_note("Setting %s channel %d to %d (%d).\n",
156 name, channel, levels - 1, current_level);
157
158 sb_mixer_set_volume_level(mixer, 0, channel, levels - 1);
159
160 current_level =
161 sb_mixer_get_volume_level(mixer, 0, channel);
162 ddf_log_note("%s channel %d set to %d.\n",
163 name, channel, current_level);
164 }
165
166}
167/*----------------------------------------------------------------------------*/
168const char * sb_mixer_type_str(sb_mixer_type_t type)
169{
170 static const char * names[] = {
171 [SB_MIXER_CT1335] = "CT 1335",
172 [SB_MIXER_CT1345] = "CT 1345",
173 [SB_MIXER_CT1745] = "CT 1745",
174 [SB_MIXER_UNKNOWN] = "Unknown mixer",
175 };
176 return names[type];
177}
178/*----------------------------------------------------------------------------*/
179int sb_mixer_init(sb_mixer_t *mixer, sb16_regs_t *regs, sb_mixer_type_t type)
180{
181 assert(mixer);
182 mixer->regs = regs;
183 mixer->type = type;
184 if (type == SB_MIXER_UNKNOWN)
185 return ENOTSUP;
186
187 if (type != SB_MIXER_NONE) {
188 pio_write_8(&regs->mixer_address, CT_MIXER_RESET_ADDRESS);
189 pio_write_8(&regs->mixer_data, 1);
190 sb_mixer_max_master_levels(mixer);
191 }
192 return EOK;
193}
194/*----------------------------------------------------------------------------*/
195int sb_mixer_get_control_item_count(const sb_mixer_t *mixer)
196{
197 assert(mixer);
198 return volume_table[mixer->type].count;
199}
200/*----------------------------------------------------------------------------*/
201int sb_mixer_get_control_item_info(const sb_mixer_t *mixer, unsigned index,
202 const char** name, unsigned *channels, unsigned *levels)
203{
204 assert(mixer);
205 if (index > volume_table[mixer->type].count)
206 return ENOENT;
207
208 const volume_item_t item = volume_table[mixer->type].table[index];
209 if (name)
210 *name = item.description;
211 if (channels)
212 *channels = item.channels;
213 if (levels)
214 *levels = item.channel_table[0].volume_levels;
215 return EOK;
216}
217/*----------------------------------------------------------------------------*/
218int sb_mixer_set_volume_level(const sb_mixer_t *mixer,
219 unsigned index, unsigned channel, unsigned level)
220{
221 if (mixer->type == SB_MIXER_UNKNOWN || mixer->type == SB_MIXER_NONE)
222 return ENOTSUP;
223 if (index >= volume_table[mixer->type].count)
224 return ENOENT;
225 if (channel >= volume_table[mixer->type].table[index].channels)
226 return ENOENT;
227 const channel_t chan =
228 volume_table[mixer->type].table[index].channel_table[channel];
229
230 if (level > chan.volume_levels)
231 level = chan.volume_levels;
232
233 pio_write_8(&mixer->regs->mixer_address, chan.address);
234 uint8_t value = 0;
235
236 if (chan.preserve_bits) {
237 value = pio_read_8(&mixer->regs->mixer_data);
238 value &= ~(uint8_t)((chan.volume_levels - 1) << chan.shift);
239 }
240
241 value |= level << chan.shift;
242 pio_write_8(&mixer->regs->mixer_data, value);
243 return EOK;
244}
245/*----------------------------------------------------------------------------*/
246unsigned sb_mixer_get_volume_level(const sb_mixer_t *mixer, unsigned index,
247 unsigned channel)
248{
249 assert(mixer);
250 if (mixer->type == SB_MIXER_UNKNOWN
251 || mixer->type == SB_MIXER_NONE
252 || (index >= volume_table[mixer->type].count)
253 || (channel >= volume_table[mixer->type].table[index].channels))
254 return 0;
255
256 const channel_t chan =
257 volume_table[mixer->type].table[index].channel_table[channel];
258 pio_write_8(&mixer->regs->mixer_address, chan.address);
259 return (pio_read_8(&mixer->regs->mixer_data) >> chan.shift)
260 & (chan.volume_levels - 1);
261}
Note: See TracBrowser for help on using the repository browser.