2 **********************************************************************
4 * Copyright 1999, 2000 Creative Labs, Inc.
6 **********************************************************************
8 * Date Author Summary of changes
9 * ---- ------ ------------------
10 * October 20, 1999 Bertrand Lee base code release
12 **********************************************************************
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License as
16 * published by the Free Software Foundation; either version 2 of
17 * the License, or (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public
25 * License along with this program; if not, write to the Free
26 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
29 **********************************************************************
35 #include "linuxsupport.h"
38 #include <linux/bitops.h>
44 int emu10k1_find_control_gpr(struct patch_manager
*mgr
, const char *patch_name
, const char *gpr_name
)
46 struct dsp_patch
*patch
;
47 struct dsp_rpatch
*rpatch
;
48 char s
[PATCH_NAME_SIZE
+ 4];
49 unsigned long *gpr_used
;
52 DPD(2, "emu10k1_find_control_gpr(): %s %s\n", patch_name
, gpr_name
);
54 rpatch
= &mgr
->rpatch
;
55 if (!strcmp(rpatch
->name
, patch_name
)) {
56 gpr_used
= rpatch
->gpr_used
;
60 for (i
= 0; i
< mgr
->current_pages
* PATCHES_PER_PAGE
; i
++) {
61 patch
= PATCH(mgr
, i
);
62 strcat(s
, patch
->name
);
63 // sprintf(s,"%s", patch->name);
65 if (!strcmp(s
, patch_name
)) {
66 gpr_used
= patch
->gpr_used
;
74 for (i
= 0; i
< NUM_GPRS
; i
++)
75 if (mgr
->gpr
[i
].type
== GPR_TYPE_CONTROL
&&
76 test_bit(i
, gpr_used
) &&
77 !strcmp(mgr
->gpr
[i
].name
, gpr_name
))
83 void emu10k1_set_control_gpr(struct emu10k1_card
*card
, int addr
, s32 val
, int flag
)
86 struct patch_manager
*mgr
= &card
->mgr
;
89 DPD(2, "emu10k1_set_control_gpr(): %d %x\n", addr
, val
);
91 if (addr
< 0 || addr
>= NUM_GPRS
)
94 //fixme: once patch manager is up, remember to fix this for the audigy
95 if (card
->is_audigy
) {
96 sblive_writeptr(card
, A_GPR_BASE
+ addr
, 0, val
);
100 val
+= sblive_readptr(card
, GPR_BASE
+ addr
, 0);
101 if (val
> mgr
->gpr
[addr
].max
)
102 val
= mgr
->gpr
[addr
].max
;
103 else if (val
< mgr
->gpr
[addr
].min
)
104 val
= mgr
->gpr
[addr
].min
;
106 sblive_writeptr(card
, GPR_BASE
+ addr
, 0, val
);
114 //TODO: make this configurable:
115 #define VOLCTRL_CHANNEL SOUND_MIXER_VOLUME
116 #define VOLCTRL_STEP_SIZE 5
118 //An internal function for setting OSS mixer controls.
119 void emu10k1_set_oss_vol(struct emu10k1_card
*card
, int oss_mixer
,
120 unsigned int left
, unsigned int right
)
122 extern char volume_params
[SOUND_MIXER_NRDEVICES
];
124 card
->ac97
.mixer_state
[oss_mixer
] = (right
<< 8) | left
;
127 card
->ac97
.write_mixer(&card
->ac97
, oss_mixer
, left
, right
);
129 emu10k1_set_volume_gpr(card
, card
->mgr
.ctrl_gpr
[oss_mixer
][0], left
,
130 volume_params
[oss_mixer
]);
132 emu10k1_set_volume_gpr(card
, card
->mgr
.ctrl_gpr
[oss_mixer
][1], right
,
133 volume_params
[oss_mixer
]);
136 //FIXME: mute should unmute when pressed a second time
137 void emu10k1_mute_irqhandler(struct emu10k1_card
*card
)
139 int oss_channel
= VOLCTRL_CHANNEL
;
145 right
= (val
>> 8) & 0xff;
148 val
= card
->ac97
.mixer_state
[oss_channel
];
153 emu10k1_set_oss_vol(card
, oss_channel
, left
, right
);
156 void emu10k1_volincr_irqhandler(struct emu10k1_card
*card
)
158 int oss_channel
= VOLCTRL_CHANNEL
;
161 left
= card
->ac97
.mixer_state
[oss_channel
] & 0xff;
162 right
= (card
->ac97
.mixer_state
[oss_channel
] >> 8) & 0xff;
164 if ((left
+= VOLCTRL_STEP_SIZE
) > 100)
167 if ((right
+= VOLCTRL_STEP_SIZE
) > 100)
170 emu10k1_set_oss_vol(card
, oss_channel
, left
, right
);
173 void emu10k1_voldecr_irqhandler(struct emu10k1_card
*card
)
175 int oss_channel
= VOLCTRL_CHANNEL
;
178 left
= card
->ac97
.mixer_state
[oss_channel
] & 0xff;
179 right
= (card
->ac97
.mixer_state
[oss_channel
] >> 8) & 0xff;
181 if ((left
-= VOLCTRL_STEP_SIZE
) < 0)
184 if ((right
-= VOLCTRL_STEP_SIZE
) < 0)
187 emu10k1_set_oss_vol(card
, oss_channel
, left
, right
);
192 void emu10k1_set_volume_gpr(struct emu10k1_card
*card
, int addr
, s32 vol
, int scale
)
195 struct patch_manager
*mgr
= &card
->mgr
;
199 static const s32 log2lin
[4] ={ // attenuation (dB)
201 0x7fffffff * 0.840896415253715 , // 1.5
202 0x7fffffff * 0.707106781186548, // 3.0
203 0x7fffffff * 0.594603557501361 , // 4.5
209 vol
= (100 - vol
) * scale
/ 100;
211 // Thanks to the comp.dsp newsgroup for this neat trick:
212 vol
= (vol
>= scale
) ? 0 : (log2lin
[vol
& 3] >> (vol
>> 2));
214 spin_lock_irqsave(&mgr
->lock
, flags
);
215 emu10k1_set_control_gpr(card
, addr
, vol
, 0);
216 spin_unlock_irqrestore(&mgr
->lock
, flags
);
221 void emu10k1_dsp_irqhandler(struct emu10k1_card
*card
)
225 if (card
->pt
.state
!= PT_STATE_INACTIVE
) {
227 bc
= sblive_readptr(card
, GPR_BASE
+ card
->pt
.intr_gpr
, 0);
229 DPD(3, "pt interrupt, bc = %d\n", bc
);
230 spin_lock_irqsave(&card
->pt
.lock
, flags
);
231 card
->pt
.blocks_played
= bc
;
232 if (card
->pt
.blocks_played
>= card
->pt
.blocks_copied
) {
233 DPF(1, "buffer underrun in passthrough playback\n");
234 emu10k1_pt_stop(card
);
236 wake_up_interruptible(&card
->pt
.wait
);
237 spin_unlock_irqrestore(&card
->pt
.lock
, flags
);