ac97.c (65490) | ac97.c (66013) |
---|---|
1/* 2 * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk> 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 * 1. Redistributions of source code must retain the above copyright --- 9 unchanged lines hidden (view full) --- 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * | 1/* 2 * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk> 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 * 1. Redistributions of source code must retain the above copyright --- 9 unchanged lines hidden (view full) --- 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * |
26 * $FreeBSD: head/sys/dev/sound/pcm/ac97.c 65490 2000-09-05 21:08:01Z cg $ | 26 * $FreeBSD: head/sys/dev/sound/pcm/ac97.c 66013 2000-09-17 23:51:00Z cg $ |
27 */ 28 29#include <dev/sound/pcm/sound.h> 30#include <dev/sound/pcm/ac97.h> 31 32struct ac97mixtable_entry { 33 int reg:8; 34 unsigned bits:4; 35 unsigned ofs:4; 36 unsigned stereo:1; 37 unsigned mute:1; 38 unsigned recidx:4; 39 unsigned mask:1; | 27 */ 28 29#include <dev/sound/pcm/sound.h> 30#include <dev/sound/pcm/ac97.h> 31 32struct ac97mixtable_entry { 33 int reg:8; 34 unsigned bits:4; 35 unsigned ofs:4; 36 unsigned stereo:1; 37 unsigned mute:1; 38 unsigned recidx:4; 39 unsigned mask:1; |
40 unsigned enable:1; |
|
40}; 41 42struct ac97_info { 43 device_t dev; 44 ac97_init *init; 45 ac97_read *read; 46 ac97_write *write; 47 void *devinfo; --- 4 unchanged lines hidden (view full) --- 52}; 53 54struct ac97_codecid { 55 u_int32_t id, noext:1; 56 char *name; 57}; 58 59static const struct ac97mixtable_entry ac97mixtable_default[32] = { | 41}; 42 43struct ac97_info { 44 device_t dev; 45 ac97_init *init; 46 ac97_read *read; 47 ac97_write *write; 48 void *devinfo; --- 4 unchanged lines hidden (view full) --- 53}; 54 55struct ac97_codecid { 56 u_int32_t id, noext:1; 57 char *name; 58}; 59 60static const struct ac97mixtable_entry ac97mixtable_default[32] = { |
60 [SOUND_MIXER_VOLUME] = { AC97_MIX_MASTER, 5, 0, 1, 1, 6, 0 }, 61 [SOUND_MIXER_BASS] = { AC97_MIX_TONE, 4, 8, 0, 0, 0, 1 }, 62 [SOUND_MIXER_TREBLE] = { AC97_MIX_TONE, 4, 0, 0, 0, 0, 1 }, 63 [SOUND_MIXER_PCM] = { AC97_MIX_PCM, 5, 0, 1, 1, 0, 0 }, 64 [SOUND_MIXER_SPEAKER] = { AC97_MIX_BEEP, 4, 1, 0, 1, 0, 0 }, 65 [SOUND_MIXER_LINE] = { AC97_MIX_LINE, 5, 0, 1, 1, 5, 0 }, 66 [SOUND_MIXER_MIC] = { AC97_MIX_MIC, 5, 0, 0, 1, 1, 0 }, 67 [SOUND_MIXER_CD] = { AC97_MIX_CD, 5, 0, 1, 1, 2, 0 }, 68 [SOUND_MIXER_LINE1] = { AC97_MIX_AUX, 5, 0, 1, 1, 4, 0 }, 69 [SOUND_MIXER_VIDEO] = { AC97_MIX_VIDEO, 5, 0, 1, 1, 3, 0 }, 70 [SOUND_MIXER_RECLEV] = { -AC97_MIX_RGAIN, 4, 0, 1, 1, 0, 0 } | 61 [SOUND_MIXER_VOLUME] = { AC97_MIX_MASTER, 5, 0, 1, 1, 6, 0, 1 }, 62 [SOUND_MIXER_MONITOR] = { AC97_MIX_PHONES, 5, 0, 1, 1, 0, 0, 0 }, 63 [SOUND_MIXER_PHONEOUT] = { AC97_MIX_MONO, 5, 0, 0, 1, 7, 0, 0 }, 64 [SOUND_MIXER_BASS] = { AC97_MIX_TONE, 4, 8, 0, 0, 0, 1, 0 }, 65 [SOUND_MIXER_TREBLE] = { AC97_MIX_TONE, 4, 0, 0, 0, 0, 1, 0 }, 66 [SOUND_MIXER_PCM] = { AC97_MIX_PCM, 5, 0, 1, 1, 0, 0, 1 }, 67 [SOUND_MIXER_SPEAKER] = { AC97_MIX_BEEP, 4, 1, 0, 1, 0, 0, 0 }, 68 [SOUND_MIXER_LINE] = { AC97_MIX_LINE, 5, 0, 1, 1, 5, 0, 1 }, 69 [SOUND_MIXER_PHONEIN] = { AC97_MIX_PHONE, 5, 0, 0, 1, 8, 0, 0 }, 70 [SOUND_MIXER_MIC] = { AC97_MIX_MIC, 5, 0, 0, 1, 1, 0, 1 }, 71 [SOUND_MIXER_CD] = { AC97_MIX_CD, 5, 0, 1, 1, 2, 0, 1 }, 72 [SOUND_MIXER_LINE1] = { AC97_MIX_AUX, 5, 0, 1, 1, 4, 0, 0 }, 73 [SOUND_MIXER_VIDEO] = { AC97_MIX_VIDEO, 5, 0, 1, 1, 3, 0, 0 }, 74 [SOUND_MIXER_RECLEV] = { -AC97_MIX_RGAIN, 4, 0, 1, 1, 0, 0, 1 } |
71}; 72 | 75}; 76 |
73static const unsigned ac97mixdevs = 74 SOUND_MASK_VOLUME | 75 SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | 76 SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_LINE1 | 77 SOUND_MASK_VIDEO | SOUND_MASK_RECLEV; 78 79static const unsigned ac97recdevs = 80 SOUND_MASK_VOLUME | SOUND_MASK_LINE | SOUND_MASK_MIC | 81 SOUND_MASK_CD | SOUND_MASK_LINE1 | SOUND_MASK_VIDEO; 82 | |
83static struct ac97_codecid ac97codecid[] = { 84 { 0x414b4d00, 1, "Asahi Kasei AK4540 rev 0" }, 85 { 0x414b4d01, 1, "Asahi Kasei AK4540 rev 1" }, 86 { 0x43525900, 0, "Cirrus Logic CS4297" }, 87 { 0x83847600, 0, "SigmaTel STAC????" }, 88 { 0x83847604, 0, "SigmaTel STAC9701/3/4/5" }, 89 { 0x83847605, 0, "SigmaTel STAC9704" }, 90 { 0x83847608, 0, "SigmaTel STAC9708" }, --- 117 unchanged lines hidden (view full) --- 208 codec->extstat = rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS; 209 return (mode == codec->extstat)? 0 : -1; 210} 211 212static int 213ac97_setrecsrc(struct ac97_info *codec, int channel) 214{ 215 struct ac97mixtable_entry *e = &codec->mix[channel]; | 77static struct ac97_codecid ac97codecid[] = { 78 { 0x414b4d00, 1, "Asahi Kasei AK4540 rev 0" }, 79 { 0x414b4d01, 1, "Asahi Kasei AK4540 rev 1" }, 80 { 0x43525900, 0, "Cirrus Logic CS4297" }, 81 { 0x83847600, 0, "SigmaTel STAC????" }, 82 { 0x83847604, 0, "SigmaTel STAC9701/3/4/5" }, 83 { 0x83847605, 0, "SigmaTel STAC9704" }, 84 { 0x83847608, 0, "SigmaTel STAC9708" }, --- 117 unchanged lines hidden (view full) --- 202 codec->extstat = rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS; 203 return (mode == codec->extstat)? 0 : -1; 204} 205 206static int 207ac97_setrecsrc(struct ac97_info *codec, int channel) 208{ 209 struct ac97mixtable_entry *e = &codec->mix[channel]; |
210 |
|
216 if (e->recidx > 0) { 217 int val = e->recidx - 1; 218 val |= val << 8; 219 wrcd(codec, AC97_REG_RECSEL, val); 220 return 0; 221 } else 222 return -1; 223} 224 225static int 226ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right) 227{ 228 struct ac97mixtable_entry *e = &codec->mix[channel]; | 211 if (e->recidx > 0) { 212 int val = e->recidx - 1; 213 val |= val << 8; 214 wrcd(codec, AC97_REG_RECSEL, val); 215 return 0; 216 } else 217 return -1; 218} 219 220static int 221ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right) 222{ 223 struct ac97mixtable_entry *e = &codec->mix[channel]; |
229 if (e->reg != 0) { | 224 225 if (e->reg && e->enable && e->bits) { |
230 int max, val, reg = (e->reg >= 0)? e->reg : -e->reg; 231 232 if (!e->stereo) 233 right = left; 234 if (e->reg > 0) { 235 left = 100 - left; 236 right = 100 - right; 237 } --- 19 unchanged lines hidden (view full) --- 257 int cur = rdcd(codec, e->reg); 258 val |= cur & ~(max << e->ofs); 259 } 260 } 261 if (left == 0 && right == 0 && e->mute == 1) 262 val = AC97_MUTE; 263 wrcd(codec, reg, val); 264 return left | (right << 8); | 226 int max, val, reg = (e->reg >= 0)? e->reg : -e->reg; 227 228 if (!e->stereo) 229 right = left; 230 if (e->reg > 0) { 231 left = 100 - left; 232 right = 100 - right; 233 } --- 19 unchanged lines hidden (view full) --- 253 int cur = rdcd(codec, e->reg); 254 val |= cur & ~(max << e->ofs); 255 } 256 } 257 if (left == 0 && right == 0 && e->mute == 1) 258 val = AC97_MUTE; 259 wrcd(codec, reg, val); 260 return left | (right << 8); |
265 } else | 261 } else { 262 /* printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable); */ |
266 return -1; | 263 return -1; |
264 } |
|
267} 268 269#if 0 270static int 271ac97_getmixer(struct ac97_info *codec, int channel) 272{ 273 struct ac97mixtable_entry *e = &codec->mix[channel]; 274 if (channel < SOUND_MIXER_NRDEVICES && e->reg != 0) { --- 13 unchanged lines hidden (view full) --- 288 } else 289 return -1; 290} 291#endif 292 293static unsigned 294ac97_initmixer(struct ac97_info *codec) 295{ | 265} 266 267#if 0 268static int 269ac97_getmixer(struct ac97_info *codec, int channel) 270{ 271 struct ac97mixtable_entry *e = &codec->mix[channel]; 272 if (channel < SOUND_MIXER_NRDEVICES && e->reg != 0) { --- 13 unchanged lines hidden (view full) --- 286 } else 287 return -1; 288} 289#endif 290 291static unsigned 292ac97_initmixer(struct ac97_info *codec) 293{ |
296 unsigned i, j; | 294 unsigned i, j, k, old; |
297 u_int32_t id; 298 299 for (i = 0; i < 32; i++) 300 codec->mix[i] = ac97mixtable_default[i]; 301 302 if (codec->init) { 303 codec->count = codec->init(codec->devinfo); 304 if (codec->count == 0) { --- 32 unchanged lines hidden (view full) --- 337 codec->extstat = 0; 338 } else { 339 i = rdcd(codec, AC97_REGEXT_ID); 340 codec->extcaps = i & 0x3fff; 341 codec->extid = (i & 0xc000) >> 14; 342 codec->extstat = rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS; 343 } 344 | 295 u_int32_t id; 296 297 for (i = 0; i < 32; i++) 298 codec->mix[i] = ac97mixtable_default[i]; 299 300 if (codec->init) { 301 codec->count = codec->init(codec->devinfo); 302 if (codec->count == 0) { --- 32 unchanged lines hidden (view full) --- 335 codec->extstat = 0; 336 } else { 337 i = rdcd(codec, AC97_REGEXT_ID); 338 codec->extcaps = i & 0x3fff; 339 codec->extid = (i & 0xc000) >> 14; 340 codec->extstat = rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS; 341 } 342 |
345 wrcd(codec, AC97_MIX_MASTER, 0x20); 346 if ((rdcd(codec, AC97_MIX_MASTER) & 0x20) == 0x20) 347 codec->mix[SOUND_MIXER_VOLUME].bits++; 348 wrcd(codec, AC97_MIX_MASTER, 0x00); | 343 for (i = 0; i < 32; i++) { 344 if (codec->mix[i].reg > 0) { 345 old = rdcd(codec, codec->mix[i].reg); 346 wrcd(codec, codec->mix[i].reg, 0x3f); 347 j = rdcd(codec, codec->mix[i].reg); 348 wrcd(codec, codec->mix[i].reg, old); 349 codec->mix[i].enable = j? 1 : 0; 350 for (k = 1; j & (1 << k); k++); 351 codec->mix[i].bits = j? k - codec->mix[i].ofs : 0; 352 } 353 /* printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits); */ 354 } |
349 350 if (bootverbose) { 351 device_printf(codec->dev, "ac97 codec id 0x%08x", id); 352 if (codec->name) 353 printf(" (%s)", codec->name); 354 printf("\n"); 355 device_printf(codec->dev, "ac97 codec features "); 356 for (i = j = 0; i < 10; i++) --- 40 unchanged lines hidden (view full) --- 397{ 398 free(codec, M_DEVBUF); 399} 400 401static int 402ac97mix_init(snd_mixer *m) 403{ 404 struct ac97_info *codec = mix_getdevinfo(m); | 355 356 if (bootverbose) { 357 device_printf(codec->dev, "ac97 codec id 0x%08x", id); 358 if (codec->name) 359 printf(" (%s)", codec->name); 360 printf("\n"); 361 device_printf(codec->dev, "ac97 codec features "); 362 for (i = j = 0; i < 10; i++) --- 40 unchanged lines hidden (view full) --- 403{ 404 free(codec, M_DEVBUF); 405} 406 407static int 408ac97mix_init(snd_mixer *m) 409{ 410 struct ac97_info *codec = mix_getdevinfo(m); |
411 u_int32_t i, mask; 412 |
|
405 if (codec == NULL) 406 return -1; | 413 if (codec == NULL) 414 return -1; |
415 |
|
407 if (ac97_initmixer(codec)) 408 return -1; | 416 if (ac97_initmixer(codec)) 417 return -1; |
409 mix_setdevs(m, ac97mixdevs | ((codec->caps & 4)? SOUND_MASK_BASS | SOUND_MASK_TREBLE : 0)); 410 mix_setrecdevs(m, ac97recdevs); | 418 419 mask = 0; 420 for (i = 0; i < 32; i++) 421 mask |= codec->mix[i].enable? 1 << i : 0; 422 mix_setdevs(m, mask); 423 424 mask = 0; 425 for (i = 0; i < 32; i++) 426 mask |= codec->mix[i].recidx? 1 << i : 0; 427 mix_setrecdevs(m, mask); |
411 return 0; 412} 413 414static int 415ac97mix_uninit(snd_mixer *m) 416{ 417 struct ac97_info *codec = mix_getdevinfo(m); | 428 return 0; 429} 430 431static int 432ac97mix_uninit(snd_mixer *m) 433{ 434 struct ac97_info *codec = mix_getdevinfo(m); |
435 |
|
418 if (codec == NULL) 419 return -1; 420 /* 421 if (ac97_uninitmixer(codec)) 422 return -1; 423 */ 424 ac97_destroy(codec); 425 return 0; 426} 427 428static int 429ac97mix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right) 430{ 431 struct ac97_info *codec = mix_getdevinfo(m); | 436 if (codec == NULL) 437 return -1; 438 /* 439 if (ac97_uninitmixer(codec)) 440 return -1; 441 */ 442 ac97_destroy(codec); 443 return 0; 444} 445 446static int 447ac97mix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right) 448{ 449 struct ac97_info *codec = mix_getdevinfo(m); |
450 |
|
432 if (codec == NULL) 433 return -1; 434 return ac97_setmixer(codec, dev, left, right); 435} 436 437static int 438ac97mix_setrecsrc(snd_mixer *m, u_int32_t src) 439{ 440 int i; 441 struct ac97_info *codec = mix_getdevinfo(m); | 451 if (codec == NULL) 452 return -1; 453 return ac97_setmixer(codec, dev, left, right); 454} 455 456static int 457ac97mix_setrecsrc(snd_mixer *m, u_int32_t src) 458{ 459 int i; 460 struct ac97_info *codec = mix_getdevinfo(m); |
461 |
|
442 if (codec == NULL) 443 return -1; 444 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) 445 if ((src & (1 << i)) != 0) 446 break; 447 return (ac97_setrecsrc(codec, i) == 0)? 1 << i : -1; 448} 449 450snd_mixer ac97_mixer = { 451 "AC97 mixer", 452 ac97mix_init, 453 ac97mix_uninit, 454 ac97mix_set, 455 ac97mix_setrecsrc, 456}; 457 | 462 if (codec == NULL) 463 return -1; 464 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) 465 if ((src & (1 << i)) != 0) 466 break; 467 return (ac97_setrecsrc(codec, i) == 0)? 1 << i : -1; 468} 469 470snd_mixer ac97_mixer = { 471 "AC97 mixer", 472 ac97mix_init, 473 ac97mix_uninit, 474 ac97mix_set, 475 ac97mix_setrecsrc, 476}; 477 |