vm: change NO_MEM to a more impossible value
[minix.git] / drivers / audio / es1370 / ak4531.c
blobcfbf194da99f6750e956a6ad1b857508dc65ebe8
1 /* best viewed with tabsize 4 */
4 #include "ak4531.h"
5 #include "pci_helper.h"
8 #define MASTER_VOLUME_LCH 0x00
9 #define MASTER_VOLUME_RCH 0x01
10 #define FM_VOLUME_LCH 0x04
11 #define FM_VOLUME_RCH 0x05
12 #define CD_AUDIO_VOLUME_LCH 0x06
13 #define CD_AUDIO_VOLUME_RCH 0x07
14 #define LINE_VOLUME_LCH 0x08
15 #define LINE_VOLUME_RCH 0x09
16 #define MIC_VOLUME 0x0e
17 #define MONO_OUT_VOLUME 0x0f
19 #define RESET_AND_POWER_DOWN 0x16
20 #define PD 0x02
21 #define RST 0x01
23 #define AD_INPUT_SELECT 0x18
24 #define MIC_AMP_GAIN 0x19
26 #define MUTE 0x80
29 static int ak4531_write(u8_t address, u8_t data);
30 static int ak4531_finished(void);
31 static int set_volume(struct volume_level *level, int cmd_left, int
32 cmd_right, int max_level);
34 static u16_t base_address;
35 static u16_t status_register;
36 static u16_t status_bit;
37 static u16_t poll_address;
39 u8_t mixer_values[0x20] = {
40 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 0x00 - 0x07 */
41 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, /* 0x08 - 0x0f */
42 0x7e, 0x3d, 0x01, 0x01, 0x00, 0x00, 0x03, 0x00, /* 0x10 - 0x17 */
43 0x00, 0x01 /* 0x18 - 0x19 */
45 #if 0
46 u8_t mixer_values[0x20] = {
47 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 0x00 - 0x07 */
48 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 0x08 - 0x0f */
49 0x7f, 0x3d, 0x55, 0x26, 0xf7, 0xef, 0x03, 0x00, /* 0x10 - 0x17 */
50 0x00, 0x01 /* 0x18 - 0x19 */
52 #endif
56 static int ak4531_finished(void) {
57 int i;
58 u16_t cstat;
59 for (i = 0; i < 0x40000; i++) {
60 cstat = pci_inw(status_register);
61 if (!(cstat & status_bit)) {
62 return 1;
65 return 0;
69 static int ak4531_write (u8_t address, u8_t data) {
70 u16_t to_be_written;
73 if (address > MIC_AMP_GAIN) return -1;
75 to_be_written = (u16_t)((address << 8) | data);
77 if (!ak4531_finished()) return -1;
78 pci_outw(base_address, to_be_written);
79 return 0;
83 int ak4531_init(u16_t base, u16_t status_reg, u16_t bit,
84 u16_t poll) {
85 int i;
87 base_address = base;
88 status_register = status_reg;
89 status_bit = bit;
90 poll_address = poll;
92 for (i=0; i<100; i++) {
93 pci_inb(poll_address);
95 if(ak4531_write(RESET_AND_POWER_DOWN, PD|RST) < 0) return -1;
97 for (i=0; i<100; i++) {
98 pci_inb(poll_address);
101 ak4531_write(AD_INPUT_SELECT, 0x00);
103 for (i = MASTER_VOLUME_LCH ; i <= MIC_AMP_GAIN; i++) {
104 if (ak4531_write(i, mixer_values[i]) < 0) return -1;
106 return 0;
110 int ak4531_get_set_volume(struct volume_level *level, int flag) {
111 int cmd_left, cmd_right, max_level;
113 max_level = 0x1f;
115 switch(level->device) {
116 case Master:
117 cmd_left = MASTER_VOLUME_LCH;
118 cmd_right = MASTER_VOLUME_RCH;
119 break;
120 case Dac:
121 return EINVAL;
122 break;
123 case Fm:
124 cmd_left = FM_VOLUME_LCH;
125 cmd_right = FM_VOLUME_RCH;
126 break;
127 case Cd:
128 cmd_left = CD_AUDIO_VOLUME_LCH;
129 cmd_right = CD_AUDIO_VOLUME_RCH;
130 break;
131 case Line:
132 cmd_left = LINE_VOLUME_LCH;
133 cmd_right = LINE_VOLUME_RCH;
134 break;
135 case Mic:
136 cmd_left = cmd_right = MIC_VOLUME;
137 break;
138 case Speaker:
139 cmd_left = cmd_right = MONO_OUT_VOLUME;
140 max_level = 0x03;
141 break;
142 case Treble:
143 return EINVAL;
144 break;
145 case Bass:
146 return EINVAL;
147 break;
148 default:
149 return EINVAL;
152 if (flag) { /* set volume */
153 return set_volume(level, cmd_left, cmd_right, max_level);
155 else { /* get volume */
156 level->left = - ((int) (mixer_values[cmd_left] & ~MUTE)) + 0x1f;
157 level->right = - ((int) (mixer_values[cmd_right] & ~MUTE)) + 0x1f;
158 return OK;
163 static int set_volume(struct volume_level *level, int cmd_left, int cmd_right,
164 int max_level) {
166 if(level->right < 0) level->right = 0;
167 else if(level->right > max_level) level->right = max_level;
168 if(level->left < 0) level->left = 0;
169 else if(level->left > max_level) level->left = max_level;
171 mixer_values[cmd_left] = (-level->left)+0x1f;
172 ak4531_write(cmd_left, mixer_values[cmd_left]);
173 mixer_values[cmd_right] = (-level->right)+0x1f;
174 ak4531_write(cmd_right, mixer_values[cmd_right]);
176 return OK;