ac97.c (113907) | ac97.c (119209) |
---|---|
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 --- 16 unchanged lines hidden (view full) --- 25 */ 26 27#include <dev/sound/pcm/sound.h> 28#include <dev/sound/pcm/ac97.h> 29#include <dev/sound/pcm/ac97_patch.h> 30 31#include "mixer_if.h" 32 | 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 --- 16 unchanged lines hidden (view full) --- 25 */ 26 27#include <dev/sound/pcm/sound.h> 28#include <dev/sound/pcm/ac97.h> 29#include <dev/sound/pcm/ac97_patch.h> 30 31#include "mixer_if.h" 32 |
33SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pcm/ac97.c 113907 2003-04-23 16:49:53Z jhb $"); | 33SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pcm/ac97.c 119209 2003-08-21 15:50:32Z orion $"); |
34 35MALLOC_DEFINE(M_AC97, "ac97", "ac97 codec"); 36 37struct ac97mixtable_entry { 38 int reg:8; /* register index */ 39 /* reg < 0 if inverted polarity */ 40 unsigned bits:4; /* width of control field */ 41 unsigned ofs:4; /* offset (only if stereo=0) */ --- 28 unchanged lines hidden (view full) --- 70 u_int8_t noext:1; 71 char *name; 72 ac97_patch patch; 73}; 74 75static const struct ac97mixtable_entry ac97mixtable_default[32] = { 76 /* [offset] reg bits of st mu re mk en */ 77 [SOUND_MIXER_VOLUME] = { AC97_MIX_MASTER, 5, 0, 1, 1, 6, 0, 1 }, | 34 35MALLOC_DEFINE(M_AC97, "ac97", "ac97 codec"); 36 37struct ac97mixtable_entry { 38 int reg:8; /* register index */ 39 /* reg < 0 if inverted polarity */ 40 unsigned bits:4; /* width of control field */ 41 unsigned ofs:4; /* offset (only if stereo=0) */ --- 28 unchanged lines hidden (view full) --- 70 u_int8_t noext:1; 71 char *name; 72 ac97_patch patch; 73}; 74 75static const struct ac97mixtable_entry ac97mixtable_default[32] = { 76 /* [offset] reg bits of st mu re mk en */ 77 [SOUND_MIXER_VOLUME] = { AC97_MIX_MASTER, 5, 0, 1, 1, 6, 0, 1 }, |
78 [SOUND_MIXER_MONITOR] = { AC97_MIX_AUXOUT, 5, 0, 1, 1, 0, 0, 0 }, | 78 [SOUND_MIXER_OGAIN] = { AC97_MIX_AUXOUT, 5, 0, 1, 1, 0, 0, 0 }, |
79 [SOUND_MIXER_PHONEOUT] = { AC97_MIX_MONO, 5, 0, 0, 1, 7, 0, 0 }, 80 [SOUND_MIXER_BASS] = { AC97_MIX_TONE, 4, 8, 0, 0, 0, 1, 0 }, 81 [SOUND_MIXER_TREBLE] = { AC97_MIX_TONE, 4, 0, 0, 0, 0, 1, 0 }, 82 [SOUND_MIXER_PCM] = { AC97_MIX_PCM, 5, 0, 1, 1, 0, 0, 1 }, 83 [SOUND_MIXER_SPEAKER] = { AC97_MIX_BEEP, 4, 1, 0, 1, 0, 0, 0 }, 84 [SOUND_MIXER_LINE] = { AC97_MIX_LINE, 5, 0, 1, 1, 5, 0, 1 }, 85 [SOUND_MIXER_PHONEIN] = { AC97_MIX_PHONE, 5, 0, 0, 1, 8, 0, 0 }, 86 [SOUND_MIXER_MIC] = { AC97_MIX_MIC, 5, 0, 0, 1, 1, 1, 1 }, --- 32 unchanged lines hidden (view full) --- 119static struct ac97_codecid ac97codecid[] = { 120 { 0x41445303, 0x00, 0, "AD1819", 0 }, 121 { 0x41445340, 0x00, 0, "AD1881", 0 }, 122 { 0x41445348, 0x00, 0, "AD1881A", 0 }, 123 { 0x41445360, 0x00, 0, "AD1885", 0 }, 124 { 0x41445361, 0x00, 0, "AD1886", ad1886_patch }, 125 { 0x41445362, 0x00, 0, "AD1887", 0 }, 126 { 0x41445363, 0x00, 0, "AD1886A", 0 }, | 79 [SOUND_MIXER_PHONEOUT] = { AC97_MIX_MONO, 5, 0, 0, 1, 7, 0, 0 }, 80 [SOUND_MIXER_BASS] = { AC97_MIX_TONE, 4, 8, 0, 0, 0, 1, 0 }, 81 [SOUND_MIXER_TREBLE] = { AC97_MIX_TONE, 4, 0, 0, 0, 0, 1, 0 }, 82 [SOUND_MIXER_PCM] = { AC97_MIX_PCM, 5, 0, 1, 1, 0, 0, 1 }, 83 [SOUND_MIXER_SPEAKER] = { AC97_MIX_BEEP, 4, 1, 0, 1, 0, 0, 0 }, 84 [SOUND_MIXER_LINE] = { AC97_MIX_LINE, 5, 0, 1, 1, 5, 0, 1 }, 85 [SOUND_MIXER_PHONEIN] = { AC97_MIX_PHONE, 5, 0, 0, 1, 8, 0, 0 }, 86 [SOUND_MIXER_MIC] = { AC97_MIX_MIC, 5, 0, 0, 1, 1, 1, 1 }, --- 32 unchanged lines hidden (view full) --- 119static struct ac97_codecid ac97codecid[] = { 120 { 0x41445303, 0x00, 0, "AD1819", 0 }, 121 { 0x41445340, 0x00, 0, "AD1881", 0 }, 122 { 0x41445348, 0x00, 0, "AD1881A", 0 }, 123 { 0x41445360, 0x00, 0, "AD1885", 0 }, 124 { 0x41445361, 0x00, 0, "AD1886", ad1886_patch }, 125 { 0x41445362, 0x00, 0, "AD1887", 0 }, 126 { 0x41445363, 0x00, 0, "AD1886A", 0 }, |
127 { 0x41445370, 0x00, 0, "AD1980", 0 }, | 127 { 0x41445370, 0x00, 0, "AD1980", ad198x_patch }, |
128 { 0x41445372, 0x00, 0, "AD1981A", 0 }, 129 { 0x41445374, 0x00, 0, "AD1981B", 0 }, | 128 { 0x41445372, 0x00, 0, "AD1981A", 0 }, 129 { 0x41445374, 0x00, 0, "AD1981B", 0 }, |
130 { 0x41445375, 0x00, 0, "AD1985", 0 }, | 130 { 0x41445375, 0x00, 0, "AD1985", ad198x_patch }, |
131 { 0x414b4d00, 0x00, 1, "AK4540", 0 }, 132 { 0x414b4d01, 0x00, 1, "AK4542", 0 }, 133 { 0x414b4d02, 0x00, 1, "AK4543", 0 }, 134 { 0x414c4320, 0x0f, 0, "ALC100", 0 }, | 131 { 0x414b4d00, 0x00, 1, "AK4540", 0 }, 132 { 0x414b4d01, 0x00, 1, "AK4542", 0 }, 133 { 0x414b4d02, 0x00, 1, "AK4543", 0 }, 134 { 0x414c4320, 0x0f, 0, "ALC100", 0 }, |
135 { 0x414c4730, 0x0f, 0, "ALC101", 0 }, | 135 { 0x414c4730, 0x0f, 0, "ALC101", 0 }, |
136 { 0x414c4710, 0x0f, 0, "ALC200", 0 }, 137 { 0x414c4740, 0x0f, 0, "ALC202", 0 }, 138 { 0x414c4720, 0x0f, 0, "ALC650", 0 }, 139 { 0x43525900, 0x07, 0, "CS4297", 0 }, 140 { 0x43525910, 0x07, 0, "CS4297A", 0 }, 141 { 0x43525920, 0x07, 0, "CS4294/98", 0 }, 142 { 0x43525930, 0x07, 0, "CS4299", 0 }, 143 { 0x43525940, 0x07, 0, "CS4201", 0 }, --- 255 unchanged lines hidden (view full) --- 399 400 if (e->reg > 0) { 401 left = 100 - left; 402 right = 100 - right; 403 } 404 405 /* 406 * For mono controls, trim val and mask, also taking | 136 { 0x414c4710, 0x0f, 0, "ALC200", 0 }, 137 { 0x414c4740, 0x0f, 0, "ALC202", 0 }, 138 { 0x414c4720, 0x0f, 0, "ALC650", 0 }, 139 { 0x43525900, 0x07, 0, "CS4297", 0 }, 140 { 0x43525910, 0x07, 0, "CS4297A", 0 }, 141 { 0x43525920, 0x07, 0, "CS4294/98", 0 }, 142 { 0x43525930, 0x07, 0, "CS4299", 0 }, 143 { 0x43525940, 0x07, 0, "CS4201", 0 }, --- 255 unchanged lines hidden (view full) --- 399 400 if (e->reg > 0) { 401 left = 100 - left; 402 right = 100 - right; 403 } 404 405 /* 406 * For mono controls, trim val and mask, also taking |
407 * care of e->ofs (offset of control field). | 407 * care of e->ofs (offset of control field). |
408 */ 409 if (e->ofs) { 410 val &= max; 411 val <<= e->ofs; 412 mask = (max << e->ofs); 413 } 414 415 /* --- 19 unchanged lines hidden (view full) --- 435 snd_mtxunlock(codec->lock); 436 return left | (right << 8); 437 } else { 438 /* printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable); */ 439 return -1; 440 } 441} 442 | 408 */ 409 if (e->ofs) { 410 val &= max; 411 val <<= e->ofs; 412 mask = (max << e->ofs); 413 } 414 415 /* --- 19 unchanged lines hidden (view full) --- 435 snd_mtxunlock(codec->lock); 436 return left | (right << 8); 437 } else { 438 /* printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable); */ 439 return -1; 440 } 441} 442 |
443#if 0 444static int 445ac97_getmixer(struct ac97_info *codec, int channel) 446{ 447 struct ac97mixtable_entry *e = &codec->mix[channel]; 448 if (channel < SOUND_MIXER_NRDEVICES && e->reg != 0) { 449 int max, val, volume; 450 451 max = (1 << e->bits) - 1; 452 val = ac97_rdcd(code, e->reg); 453 if (val == AC97_MUTE && e->mute == 1) 454 volume = 0; 455 else { 456 if (e->stereo == 0) val >>= e->ofs; 457 val &= max; 458 volume = (val * 100) / max; 459 if (e->reg > 0) volume = 100 - volume; 460 } 461 return volume; 462 } else 463 return -1; 464} 465#endif 466 | |
467static void 468ac97_fix_auxout(struct ac97_info *codec) 469{ | 443static void 444ac97_fix_auxout(struct ac97_info *codec) 445{ |
470 /* Determine what AUXOUT really means, it can be: | 446 /* 447 * Determine if AUX_OUT is a valid control. |
471 * | 448 * |
449 * Control will read zero if not valid after a reset, other gain 450 * controls read muted (0x8000). 451 */ 452 if (ac97_rdcd(codec, AC97_MIX_AUXOUT) == 0) { 453 bzero(&codec->mix[SOUND_MIXER_OGAIN], 454 sizeof(codec->mix[SOUND_MIXER_OGAIN])); 455 } 456 457 /* 458 * Determine what AUX_OUT really means, it can be: 459 * |
|
472 * 1. Headphone out. 473 * 2. 4-Channel Out 474 * 3. True line level out (effectively master volume). 475 * 476 * See Sections 5.2.1 and 5.27 for AUX_OUT Options in AC97r2.{2,3}. 477 */ | 460 * 1. Headphone out. 461 * 2. 4-Channel Out 462 * 3. True line level out (effectively master volume). 463 * 464 * See Sections 5.2.1 and 5.27 for AUX_OUT Options in AC97r2.{2,3}. 465 */ |
478 if (codec->caps & AC97_CAP_HEADPHONE) { 479 /* XXX We should probably check the AUX_OUT initial value. 480 * Leave AC97_MIX_AUXOUT - SOUND_MIXER_MONITOR relationship */ 481 return; 482 } else if (codec->extcaps & AC97_EXTCAP_SDAC && 483 ac97_rdcd(codec, AC97_MIXEXT_SURROUND) == 0x8080) { 484 /* 4-Channel Out, add an additional gain setting. */ 485 codec->mix[SOUND_MIXER_OGAIN] = codec->mix[SOUND_MIXER_MONITOR]; 486 } else { 487 /* Master volume is/maybe fixed in h/w, not sufficiently 488 * clear in spec to blat SOUND_MIXER_MASTER. */ 489 codec->mix[SOUND_MIXER_OGAIN] = codec->mix[SOUND_MIXER_MONITOR]; | 466 if (codec->extcaps & AC97_EXTCAP_SDAC && 467 ac97_rdcd(codec, AC97_MIXEXT_SURROUND) == 0x8080) { 468 codec->mix[SOUND_MIXER_VOLUME].reg = AC97_MIXEXT_SURROUND; 469 } else if (codec->caps & AC97_CAP_HEADPHONE) { 470 /* Headphone out present/selected AUX_OUT is effectively 471 * master volume control. */ 472 struct ac97mixtable_entry tmp = codec->mix[SOUND_MIXER_VOLUME]; 473 codec->mix[SOUND_MIXER_VOLUME] = codec->mix[SOUND_MIXER_OGAIN]; 474 codec->mix[SOUND_MIXER_OGAIN] = tmp; |
490 } | 475 } |
491 /* Blat monitor, inappropriate label if we get here */ 492 bzero(&codec->mix[SOUND_MIXER_MONITOR], 493 sizeof(codec->mix[SOUND_MIXER_MONITOR])); | |
494} 495 | 476} 477 |
478static void 479ac97_fix_tone(struct ac97_info *codec) 480{ 481 /* Hide treble and bass if they don't exist */ 482 if ((codec->caps & AC97_CAP_TONE) == 0) { 483 bzero(&codec->mix[SOUND_MIXER_BASS], 484 sizeof(codec->mix[SOUND_MIXER_BASS])); 485 bzero(&codec->mix[SOUND_MIXER_TREBLE], 486 sizeof(codec->mix[SOUND_MIXER_TREBLE])); 487 } 488} 489 |
|
496static const char* 497ac97_hw_desc(u_int32_t id, const char* vname, const char* cname, char* buf) 498{ 499 if (cname == NULL) { 500 sprintf(buf, "Unknown AC97 Codec (id = 0x%08x)", id); 501 return buf; 502 } 503 504 if (vname == NULL) vname = "Unknown"; | 490static const char* 491ac97_hw_desc(u_int32_t id, const char* vname, const char* cname, char* buf) 492{ 493 if (cname == NULL) { 494 sprintf(buf, "Unknown AC97 Codec (id = 0x%08x)", id); 495 return buf; 496 } 497 498 if (vname == NULL) vname = "Unknown"; |
505 | 499 |
506 if (bootverbose) { 507 sprintf(buf, "%s %s AC97 Codec (id = 0x%08x)", vname, cname, id); 508 } else { 509 sprintf(buf, "%s %s AC97 Codec", vname, cname); 510 } 511 return buf; 512} 513 --- 67 unchanged lines hidden (view full) --- 581 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS; 582 } 583 } 584 585 for (i = 0; i < 32; i++) { 586 codec->mix[i] = ac97mixtable_default[i]; 587 } 588 ac97_fix_auxout(codec); | 500 if (bootverbose) { 501 sprintf(buf, "%s %s AC97 Codec (id = 0x%08x)", vname, cname, id); 502 } else { 503 sprintf(buf, "%s %s AC97 Codec", vname, cname); 504 } 505 return buf; 506} 507 --- 67 unchanged lines hidden (view full) --- 575 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS; 576 } 577 } 578 579 for (i = 0; i < 32; i++) { 580 codec->mix[i] = ac97mixtable_default[i]; 581 } 582 ac97_fix_auxout(codec); |
583 ac97_fix_tone(codec); |
|
589 if (codec_patch) 590 codec_patch(codec); 591 592 for (i = 0; i < 32; i++) { 593 k = codec->noext? codec->mix[i].enable : 1; 594 if (k && (codec->mix[i].reg > 0)) { 595 old = ac97_rdcd(codec, codec->mix[i].reg); 596 ac97_wrcd(codec, codec->mix[i].reg, 0x3f); --- 210 unchanged lines hidden --- | 584 if (codec_patch) 585 codec_patch(codec); 586 587 for (i = 0; i < 32; i++) { 588 k = codec->noext? codec->mix[i].enable : 1; 589 if (k && (codec->mix[i].reg > 0)) { 590 old = ac97_rdcd(codec, codec->mix[i].reg); 591 ac97_wrcd(codec, codec->mix[i].reg, 0x3f); --- 210 unchanged lines hidden --- |