sb_mixer.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995
  1. /*
  2. * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
  3. * Routines for Sound Blaster mixer control
  4. *
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19. *
  20. */
  21. #include <asm/io.h>
  22. #include <linux/delay.h>
  23. #include <linux/time.h>
  24. #include <sound/core.h>
  25. #include <sound/sb.h>
  26. #include <sound/control.h>
  27. #undef IO_DEBUG
  28. void snd_sbmixer_write(struct snd_sb *chip, unsigned char reg, unsigned char data)
  29. {
  30. outb(reg, SBP(chip, MIXER_ADDR));
  31. udelay(10);
  32. outb(data, SBP(chip, MIXER_DATA));
  33. udelay(10);
  34. #ifdef IO_DEBUG
  35. snd_printk(KERN_DEBUG "mixer_write 0x%x 0x%x\n", reg, data);
  36. #endif
  37. }
  38. unsigned char snd_sbmixer_read(struct snd_sb *chip, unsigned char reg)
  39. {
  40. unsigned char result;
  41. outb(reg, SBP(chip, MIXER_ADDR));
  42. udelay(10);
  43. result = inb(SBP(chip, MIXER_DATA));
  44. udelay(10);
  45. #ifdef IO_DEBUG
  46. snd_printk(KERN_DEBUG "mixer_read 0x%x 0x%x\n", reg, result);
  47. #endif
  48. return result;
  49. }
  50. /*
  51. * Single channel mixer element
  52. */
  53. static int snd_sbmixer_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
  54. {
  55. int mask = (kcontrol->private_value >> 24) & 0xff;
  56. uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
  57. uinfo->count = 1;
  58. uinfo->value.integer.min = 0;
  59. uinfo->value.integer.max = mask;
  60. return 0;
  61. }
  62. static int snd_sbmixer_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
  63. {
  64. struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
  65. unsigned long flags;
  66. int reg = kcontrol->private_value & 0xff;
  67. int shift = (kcontrol->private_value >> 16) & 0xff;
  68. int mask = (kcontrol->private_value >> 24) & 0xff;
  69. unsigned char val;
  70. spin_lock_irqsave(&sb->mixer_lock, flags);
  71. val = (snd_sbmixer_read(sb, reg) >> shift) & mask;
  72. spin_unlock_irqrestore(&sb->mixer_lock, flags);
  73. ucontrol->value.integer.value[0] = val;
  74. return 0;
  75. }
  76. static int snd_sbmixer_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
  77. {
  78. struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
  79. unsigned long flags;
  80. int reg = kcontrol->private_value & 0xff;
  81. int shift = (kcontrol->private_value >> 16) & 0x07;
  82. int mask = (kcontrol->private_value >> 24) & 0xff;
  83. int change;
  84. unsigned char val, oval;
  85. val = (ucontrol->value.integer.value[0] & mask) << shift;
  86. spin_lock_irqsave(&sb->mixer_lock, flags);
  87. oval = snd_sbmixer_read(sb, reg);
  88. val = (oval & ~(mask << shift)) | val;
  89. change = val != oval;
  90. if (change)
  91. snd_sbmixer_write(sb, reg, val);
  92. spin_unlock_irqrestore(&sb->mixer_lock, flags);
  93. return change;
  94. }
  95. /*
  96. * Double channel mixer element
  97. */
  98. static int snd_sbmixer_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
  99. {
  100. int mask = (kcontrol->private_value >> 24) & 0xff;
  101. uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
  102. uinfo->count = 2;
  103. uinfo->value.integer.min = 0;
  104. uinfo->value.integer.max = mask;
  105. return 0;
  106. }
  107. static int snd_sbmixer_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
  108. {
  109. struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
  110. unsigned long flags;
  111. int left_reg = kcontrol->private_value & 0xff;
  112. int right_reg = (kcontrol->private_value >> 8) & 0xff;
  113. int left_shift = (kcontrol->private_value >> 16) & 0x07;
  114. int right_shift = (kcontrol->private_value >> 19) & 0x07;
  115. int mask = (kcontrol->private_value >> 24) & 0xff;
  116. unsigned char left, right;
  117. spin_lock_irqsave(&sb->mixer_lock, flags);
  118. left = (snd_sbmixer_read(sb, left_reg) >> left_shift) & mask;
  119. right = (snd_sbmixer_read(sb, right_reg) >> right_shift) & mask;
  120. spin_unlock_irqrestore(&sb->mixer_lock, flags);
  121. ucontrol->value.integer.value[0] = left;
  122. ucontrol->value.integer.value[1] = right;
  123. return 0;
  124. }
  125. static int snd_sbmixer_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
  126. {
  127. struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
  128. unsigned long flags;
  129. int left_reg = kcontrol->private_value & 0xff;
  130. int right_reg = (kcontrol->private_value >> 8) & 0xff;
  131. int left_shift = (kcontrol->private_value >> 16) & 0x07;
  132. int right_shift = (kcontrol->private_value >> 19) & 0x07;
  133. int mask = (kcontrol->private_value >> 24) & 0xff;
  134. int change;
  135. unsigned char left, right, oleft, oright;
  136. left = (ucontrol->value.integer.value[0] & mask) << left_shift;
  137. right = (ucontrol->value.integer.value[1] & mask) << right_shift;
  138. spin_lock_irqsave(&sb->mixer_lock, flags);
  139. if (left_reg == right_reg) {
  140. oleft = snd_sbmixer_read(sb, left_reg);
  141. left = (oleft & ~((mask << left_shift) | (mask << right_shift))) | left | right;
  142. change = left != oleft;
  143. if (change)
  144. snd_sbmixer_write(sb, left_reg, left);
  145. } else {
  146. oleft = snd_sbmixer_read(sb, left_reg);
  147. oright = snd_sbmixer_read(sb, right_reg);
  148. left = (oleft & ~(mask << left_shift)) | left;
  149. right = (oright & ~(mask << right_shift)) | right;
  150. change = left != oleft || right != oright;
  151. if (change) {
  152. snd_sbmixer_write(sb, left_reg, left);
  153. snd_sbmixer_write(sb, right_reg, right);
  154. }
  155. }
  156. spin_unlock_irqrestore(&sb->mixer_lock, flags);
  157. return change;
  158. }
  159. /*
  160. * DT-019x / ALS-007 capture/input switch
  161. */
  162. static int snd_dt019x_input_sw_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
  163. {
  164. static char *texts[5] = {
  165. "CD", "Mic", "Line", "Synth", "Master"
  166. };
  167. uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
  168. uinfo->count = 1;
  169. uinfo->value.enumerated.items = 5;
  170. if (uinfo->value.enumerated.item > 4)
  171. uinfo->value.enumerated.item = 4;
  172. strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
  173. return 0;
  174. }
  175. static int snd_dt019x_input_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
  176. {
  177. struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
  178. unsigned long flags;
  179. unsigned char oval;
  180. spin_lock_irqsave(&sb->mixer_lock, flags);
  181. oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW);
  182. spin_unlock_irqrestore(&sb->mixer_lock, flags);
  183. switch (oval & 0x07) {
  184. case SB_DT019X_CAP_CD:
  185. ucontrol->value.enumerated.item[0] = 0;
  186. break;
  187. case SB_DT019X_CAP_MIC:
  188. ucontrol->value.enumerated.item[0] = 1;
  189. break;
  190. case SB_DT019X_CAP_LINE:
  191. ucontrol->value.enumerated.item[0] = 2;
  192. break;
  193. case SB_DT019X_CAP_MAIN:
  194. ucontrol->value.enumerated.item[0] = 4;
  195. break;
  196. /* To record the synth on these cards you must record the main. */
  197. /* Thus SB_DT019X_CAP_SYNTH == SB_DT019X_CAP_MAIN and would cause */
  198. /* duplicate case labels if left uncommented. */
  199. /* case SB_DT019X_CAP_SYNTH:
  200. * ucontrol->value.enumerated.item[0] = 3;
  201. * break;
  202. */
  203. default:
  204. ucontrol->value.enumerated.item[0] = 4;
  205. break;
  206. }
  207. return 0;
  208. }
  209. static int snd_dt019x_input_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
  210. {
  211. struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
  212. unsigned long flags;
  213. int change;
  214. unsigned char nval, oval;
  215. if (ucontrol->value.enumerated.item[0] > 4)
  216. return -EINVAL;
  217. switch (ucontrol->value.enumerated.item[0]) {
  218. case 0:
  219. nval = SB_DT019X_CAP_CD;
  220. break;
  221. case 1:
  222. nval = SB_DT019X_CAP_MIC;
  223. break;
  224. case 2:
  225. nval = SB_DT019X_CAP_LINE;
  226. break;
  227. case 3:
  228. nval = SB_DT019X_CAP_SYNTH;
  229. break;
  230. case 4:
  231. nval = SB_DT019X_CAP_MAIN;
  232. break;
  233. default:
  234. nval = SB_DT019X_CAP_MAIN;
  235. }
  236. spin_lock_irqsave(&sb->mixer_lock, flags);
  237. oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW);
  238. change = nval != oval;
  239. if (change)
  240. snd_sbmixer_write(sb, SB_DT019X_CAPTURE_SW, nval);
  241. spin_unlock_irqrestore(&sb->mixer_lock, flags);
  242. return change;
  243. }
  244. /*
  245. * SBPRO input multiplexer
  246. */
  247. static int snd_sb8mixer_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
  248. {
  249. static char *texts[3] = {
  250. "Mic", "CD", "Line"
  251. };
  252. uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
  253. uinfo->count = 1;
  254. uinfo->value.enumerated.items = 3;
  255. if (uinfo->value.enumerated.item > 2)
  256. uinfo->value.enumerated.item = 2;
  257. strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
  258. return 0;
  259. }
  260. static int snd_sb8mixer_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
  261. {
  262. struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
  263. unsigned long flags;
  264. unsigned char oval;
  265. spin_lock_irqsave(&sb->mixer_lock, flags);
  266. oval = snd_sbmixer_read(sb, SB_DSP_CAPTURE_SOURCE);
  267. spin_unlock_irqrestore(&sb->mixer_lock, flags);
  268. switch ((oval >> 0x01) & 0x03) {
  269. case SB_DSP_MIXS_CD:
  270. ucontrol->value.enumerated.item[0] = 1;
  271. break;
  272. case SB_DSP_MIXS_LINE:
  273. ucontrol->value.enumerated.item[0] = 2;
  274. break;
  275. default:
  276. ucontrol->value.enumerated.item[0] = 0;
  277. break;
  278. }
  279. return 0;
  280. }
  281. static int snd_sb8mixer_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
  282. {
  283. struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
  284. unsigned long flags;
  285. int change;
  286. unsigned char nval, oval;
  287. if (ucontrol->value.enumerated.item[0] > 2)
  288. return -EINVAL;
  289. switch (ucontrol->value.enumerated.item[0]) {
  290. case 1:
  291. nval = SB_DSP_MIXS_CD;
  292. break;
  293. case 2:
  294. nval = SB_DSP_MIXS_LINE;
  295. break;
  296. default:
  297. nval = SB_DSP_MIXS_MIC;
  298. }
  299. nval <<= 1;
  300. spin_lock_irqsave(&sb->mixer_lock, flags);
  301. oval = snd_sbmixer_read(sb, SB_DSP_CAPTURE_SOURCE);
  302. nval |= oval & ~0x06;
  303. change = nval != oval;
  304. if (change)
  305. snd_sbmixer_write(sb, SB_DSP_CAPTURE_SOURCE, nval);
  306. spin_unlock_irqrestore(&sb->mixer_lock, flags);
  307. return change;
  308. }
  309. /*
  310. * SB16 input switch
  311. */
  312. static int snd_sb16mixer_info_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
  313. {
  314. uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
  315. uinfo->count = 4;
  316. uinfo->value.integer.min = 0;
  317. uinfo->value.integer.max = 1;
  318. return 0;
  319. }
  320. static int snd_sb16mixer_get_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
  321. {
  322. struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
  323. unsigned long flags;
  324. int reg1 = kcontrol->private_value & 0xff;
  325. int reg2 = (kcontrol->private_value >> 8) & 0xff;
  326. int left_shift = (kcontrol->private_value >> 16) & 0x0f;
  327. int right_shift = (kcontrol->private_value >> 24) & 0x0f;
  328. unsigned char val1, val2;
  329. spin_lock_irqsave(&sb->mixer_lock, flags);
  330. val1 = snd_sbmixer_read(sb, reg1);
  331. val2 = snd_sbmixer_read(sb, reg2);
  332. spin_unlock_irqrestore(&sb->mixer_lock, flags);
  333. ucontrol->value.integer.value[0] = (val1 >> left_shift) & 0x01;
  334. ucontrol->value.integer.value[1] = (val2 >> left_shift) & 0x01;
  335. ucontrol->value.integer.value[2] = (val1 >> right_shift) & 0x01;
  336. ucontrol->value.integer.value[3] = (val2 >> right_shift) & 0x01;
  337. return 0;
  338. }
  339. static int snd_sb16mixer_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
  340. {
  341. struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
  342. unsigned long flags;
  343. int reg1 = kcontrol->private_value & 0xff;
  344. int reg2 = (kcontrol->private_value >> 8) & 0xff;
  345. int left_shift = (kcontrol->private_value >> 16) & 0x0f;
  346. int right_shift = (kcontrol->private_value >> 24) & 0x0f;
  347. int change;
  348. unsigned char val1, val2, oval1, oval2;
  349. spin_lock_irqsave(&sb->mixer_lock, flags);
  350. oval1 = snd_sbmixer_read(sb, reg1);
  351. oval2 = snd_sbmixer_read(sb, reg2);
  352. val1 = oval1 & ~((1 << left_shift) | (1 << right_shift));
  353. val2 = oval2 & ~((1 << left_shift) | (1 << right_shift));
  354. val1 |= (ucontrol->value.integer.value[0] & 1) << left_shift;
  355. val2 |= (ucontrol->value.integer.value[1] & 1) << left_shift;
  356. val1 |= (ucontrol->value.integer.value[2] & 1) << right_shift;
  357. val2 |= (ucontrol->value.integer.value[3] & 1) << right_shift;
  358. change = val1 != oval1 || val2 != oval2;
  359. if (change) {
  360. snd_sbmixer_write(sb, reg1, val1);
  361. snd_sbmixer_write(sb, reg2, val2);
  362. }
  363. spin_unlock_irqrestore(&sb->mixer_lock, flags);
  364. return change;
  365. }
  366. /*
  367. */
  368. /*
  369. */
  370. int snd_sbmixer_add_ctl(struct snd_sb *chip, const char *name, int index, int type, unsigned long value)
  371. {
  372. static struct snd_kcontrol_new newctls[] = {
  373. [SB_MIX_SINGLE] = {
  374. .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  375. .info = snd_sbmixer_info_single,
  376. .get = snd_sbmixer_get_single,
  377. .put = snd_sbmixer_put_single,
  378. },
  379. [SB_MIX_DOUBLE] = {
  380. .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  381. .info = snd_sbmixer_info_double,
  382. .get = snd_sbmixer_get_double,
  383. .put = snd_sbmixer_put_double,
  384. },
  385. [SB_MIX_INPUT_SW] = {
  386. .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  387. .info = snd_sb16mixer_info_input_sw,
  388. .get = snd_sb16mixer_get_input_sw,
  389. .put = snd_sb16mixer_put_input_sw,
  390. },
  391. [SB_MIX_CAPTURE_PRO] = {
  392. .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  393. .info = snd_sb8mixer_info_mux,
  394. .get = snd_sb8mixer_get_mux,
  395. .put = snd_sb8mixer_put_mux,
  396. },
  397. [SB_MIX_CAPTURE_DT019X] = {
  398. .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  399. .info = snd_dt019x_input_sw_info,
  400. .get = snd_dt019x_input_sw_get,
  401. .put = snd_dt019x_input_sw_put,
  402. },
  403. };
  404. struct snd_kcontrol *ctl;
  405. int err;
  406. ctl = snd_ctl_new1(&newctls[type], chip);
  407. if (! ctl)
  408. return -ENOMEM;
  409. strlcpy(ctl->id.name, name, sizeof(ctl->id.name));
  410. ctl->id.index = index;
  411. ctl->private_value = value;
  412. if ((err = snd_ctl_add(chip->card, ctl)) < 0)
  413. return err;
  414. return 0;
  415. }
  416. /*
  417. * SB 2.0 specific mixer elements
  418. */
  419. static struct sbmix_elem snd_sb20_ctl_master_play_vol =
  420. SB_SINGLE("Master Playback Volume", SB_DSP20_MASTER_DEV, 1, 7);
  421. static struct sbmix_elem snd_sb20_ctl_pcm_play_vol =
  422. SB_SINGLE("PCM Playback Volume", SB_DSP20_PCM_DEV, 1, 3);
  423. static struct sbmix_elem snd_sb20_ctl_synth_play_vol =
  424. SB_SINGLE("Synth Playback Volume", SB_DSP20_FM_DEV, 1, 7);
  425. static struct sbmix_elem snd_sb20_ctl_cd_play_vol =
  426. SB_SINGLE("CD Playback Volume", SB_DSP20_CD_DEV, 1, 7);
  427. static struct sbmix_elem *snd_sb20_controls[] = {
  428. &snd_sb20_ctl_master_play_vol,
  429. &snd_sb20_ctl_pcm_play_vol,
  430. &snd_sb20_ctl_synth_play_vol,
  431. &snd_sb20_ctl_cd_play_vol
  432. };
  433. static unsigned char snd_sb20_init_values[][2] = {
  434. { SB_DSP20_MASTER_DEV, 0 },
  435. { SB_DSP20_FM_DEV, 0 },
  436. };
  437. /*
  438. * SB Pro specific mixer elements
  439. */
  440. static struct sbmix_elem snd_sbpro_ctl_master_play_vol =
  441. SB_DOUBLE("Master Playback Volume", SB_DSP_MASTER_DEV, SB_DSP_MASTER_DEV, 5, 1, 7);
  442. static struct sbmix_elem snd_sbpro_ctl_pcm_play_vol =
  443. SB_DOUBLE("PCM Playback Volume", SB_DSP_PCM_DEV, SB_DSP_PCM_DEV, 5, 1, 7);
  444. static struct sbmix_elem snd_sbpro_ctl_pcm_play_filter =
  445. SB_SINGLE("PCM Playback Filter", SB_DSP_PLAYBACK_FILT, 5, 1);
  446. static struct sbmix_elem snd_sbpro_ctl_synth_play_vol =
  447. SB_DOUBLE("Synth Playback Volume", SB_DSP_FM_DEV, SB_DSP_FM_DEV, 5, 1, 7);
  448. static struct sbmix_elem snd_sbpro_ctl_cd_play_vol =
  449. SB_DOUBLE("CD Playback Volume", SB_DSP_CD_DEV, SB_DSP_CD_DEV, 5, 1, 7);
  450. static struct sbmix_elem snd_sbpro_ctl_line_play_vol =
  451. SB_DOUBLE("Line Playback Volume", SB_DSP_LINE_DEV, SB_DSP_LINE_DEV, 5, 1, 7);
  452. static struct sbmix_elem snd_sbpro_ctl_mic_play_vol =
  453. SB_SINGLE("Mic Playback Volume", SB_DSP_MIC_DEV, 1, 3);
  454. static struct sbmix_elem snd_sbpro_ctl_capture_source =
  455. {
  456. .name = "Capture Source",
  457. .type = SB_MIX_CAPTURE_PRO
  458. };
  459. static struct sbmix_elem snd_sbpro_ctl_capture_filter =
  460. SB_SINGLE("Capture Filter", SB_DSP_CAPTURE_FILT, 5, 1);
  461. static struct sbmix_elem snd_sbpro_ctl_capture_low_filter =
  462. SB_SINGLE("Capture Low-Pass Filter", SB_DSP_CAPTURE_FILT, 3, 1);
  463. static struct sbmix_elem *snd_sbpro_controls[] = {
  464. &snd_sbpro_ctl_master_play_vol,
  465. &snd_sbpro_ctl_pcm_play_vol,
  466. &snd_sbpro_ctl_pcm_play_filter,
  467. &snd_sbpro_ctl_synth_play_vol,
  468. &snd_sbpro_ctl_cd_play_vol,
  469. &snd_sbpro_ctl_line_play_vol,
  470. &snd_sbpro_ctl_mic_play_vol,
  471. &snd_sbpro_ctl_capture_source,
  472. &snd_sbpro_ctl_capture_filter,
  473. &snd_sbpro_ctl_capture_low_filter
  474. };
  475. static unsigned char snd_sbpro_init_values[][2] = {
  476. { SB_DSP_MASTER_DEV, 0 },
  477. { SB_DSP_PCM_DEV, 0 },
  478. { SB_DSP_FM_DEV, 0 },
  479. };
  480. /*
  481. * SB16 specific mixer elements
  482. */
  483. static struct sbmix_elem snd_sb16_ctl_master_play_vol =
  484. SB_DOUBLE("Master Playback Volume", SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31);
  485. static struct sbmix_elem snd_sb16_ctl_3d_enhance_switch =
  486. SB_SINGLE("3D Enhancement Switch", SB_DSP4_3DSE, 0, 1);
  487. static struct sbmix_elem snd_sb16_ctl_tone_bass =
  488. SB_DOUBLE("Tone Control - Bass", SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15);
  489. static struct sbmix_elem snd_sb16_ctl_tone_treble =
  490. SB_DOUBLE("Tone Control - Treble", SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15);
  491. static struct sbmix_elem snd_sb16_ctl_pcm_play_vol =
  492. SB_DOUBLE("PCM Playback Volume", SB_DSP4_PCM_DEV, (SB_DSP4_PCM_DEV + 1), 3, 3, 31);
  493. static struct sbmix_elem snd_sb16_ctl_synth_capture_route =
  494. SB16_INPUT_SW("Synth Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 6, 5);
  495. static struct sbmix_elem snd_sb16_ctl_synth_play_vol =
  496. SB_DOUBLE("Synth Playback Volume", SB_DSP4_SYNTH_DEV, (SB_DSP4_SYNTH_DEV + 1), 3, 3, 31);
  497. static struct sbmix_elem snd_sb16_ctl_cd_capture_route =
  498. SB16_INPUT_SW("CD Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 2, 1);
  499. static struct sbmix_elem snd_sb16_ctl_cd_play_switch =
  500. SB_DOUBLE("CD Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1);
  501. static struct sbmix_elem snd_sb16_ctl_cd_play_vol =
  502. SB_DOUBLE("CD Playback Volume", SB_DSP4_CD_DEV, (SB_DSP4_CD_DEV + 1), 3, 3, 31);
  503. static struct sbmix_elem snd_sb16_ctl_line_capture_route =
  504. SB16_INPUT_SW("Line Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 4, 3);
  505. static struct sbmix_elem snd_sb16_ctl_line_play_switch =
  506. SB_DOUBLE("Line Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1);
  507. static struct sbmix_elem snd_sb16_ctl_line_play_vol =
  508. SB_DOUBLE("Line Playback Volume", SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31);
  509. static struct sbmix_elem snd_sb16_ctl_mic_capture_route =
  510. SB16_INPUT_SW("Mic Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0);
  511. static struct sbmix_elem snd_sb16_ctl_mic_play_switch =
  512. SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1);
  513. static struct sbmix_elem snd_sb16_ctl_mic_play_vol =
  514. SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31);
  515. static struct sbmix_elem snd_sb16_ctl_pc_speaker_vol =
  516. SB_SINGLE("PC Speaker Volume", SB_DSP4_SPEAKER_DEV, 6, 3);
  517. static struct sbmix_elem snd_sb16_ctl_capture_vol =
  518. SB_DOUBLE("Capture Volume", SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3);
  519. static struct sbmix_elem snd_sb16_ctl_play_vol =
  520. SB_DOUBLE("Playback Volume", SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3);
  521. static struct sbmix_elem snd_sb16_ctl_auto_mic_gain =
  522. SB_SINGLE("Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1);
  523. static struct sbmix_elem *snd_sb16_controls[] = {
  524. &snd_sb16_ctl_master_play_vol,
  525. &snd_sb16_ctl_3d_enhance_switch,
  526. &snd_sb16_ctl_tone_bass,
  527. &snd_sb16_ctl_tone_treble,
  528. &snd_sb16_ctl_pcm_play_vol,
  529. &snd_sb16_ctl_synth_capture_route,
  530. &snd_sb16_ctl_synth_play_vol,
  531. &snd_sb16_ctl_cd_capture_route,
  532. &snd_sb16_ctl_cd_play_switch,
  533. &snd_sb16_ctl_cd_play_vol,
  534. &snd_sb16_ctl_line_capture_route,
  535. &snd_sb16_ctl_line_play_switch,
  536. &snd_sb16_ctl_line_play_vol,
  537. &snd_sb16_ctl_mic_capture_route,
  538. &snd_sb16_ctl_mic_play_switch,
  539. &snd_sb16_ctl_mic_play_vol,
  540. &snd_sb16_ctl_pc_speaker_vol,
  541. &snd_sb16_ctl_capture_vol,
  542. &snd_sb16_ctl_play_vol,
  543. &snd_sb16_ctl_auto_mic_gain
  544. };
  545. static unsigned char snd_sb16_init_values[][2] = {
  546. { SB_DSP4_MASTER_DEV + 0, 0 },
  547. { SB_DSP4_MASTER_DEV + 1, 0 },
  548. { SB_DSP4_PCM_DEV + 0, 0 },
  549. { SB_DSP4_PCM_DEV + 1, 0 },
  550. { SB_DSP4_SYNTH_DEV + 0, 0 },
  551. { SB_DSP4_SYNTH_DEV + 1, 0 },
  552. { SB_DSP4_INPUT_LEFT, 0 },
  553. { SB_DSP4_INPUT_RIGHT, 0 },
  554. { SB_DSP4_OUTPUT_SW, 0 },
  555. { SB_DSP4_SPEAKER_DEV, 0 },
  556. };
  557. /*
  558. * DT019x specific mixer elements
  559. */
  560. static struct sbmix_elem snd_dt019x_ctl_master_play_vol =
  561. SB_DOUBLE("Master Playback Volume", SB_DT019X_MASTER_DEV, SB_DT019X_MASTER_DEV, 4,0, 15);
  562. static struct sbmix_elem snd_dt019x_ctl_pcm_play_vol =
  563. SB_DOUBLE("PCM Playback Volume", SB_DT019X_PCM_DEV, SB_DT019X_PCM_DEV, 4,0, 15);
  564. static struct sbmix_elem snd_dt019x_ctl_synth_play_vol =
  565. SB_DOUBLE("Synth Playback Volume", SB_DT019X_SYNTH_DEV, SB_DT019X_SYNTH_DEV, 4,0, 15);
  566. static struct sbmix_elem snd_dt019x_ctl_cd_play_vol =
  567. SB_DOUBLE("CD Playback Volume", SB_DT019X_CD_DEV, SB_DT019X_CD_DEV, 4,0, 15);
  568. static struct sbmix_elem snd_dt019x_ctl_mic_play_vol =
  569. SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7);
  570. static struct sbmix_elem snd_dt019x_ctl_pc_speaker_vol =
  571. SB_SINGLE("PC Speaker Volume", SB_DT019X_SPKR_DEV, 0, 7);
  572. static struct sbmix_elem snd_dt019x_ctl_line_play_vol =
  573. SB_DOUBLE("Line Playback Volume", SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4,0, 15);
  574. static struct sbmix_elem snd_dt019x_ctl_pcm_play_switch =
  575. SB_DOUBLE("PCM Playback Switch", SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2,1, 1);
  576. static struct sbmix_elem snd_dt019x_ctl_synth_play_switch =
  577. SB_DOUBLE("Synth Playback Switch", SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4,3, 1);
  578. static struct sbmix_elem snd_dt019x_ctl_capture_source =
  579. {
  580. .name = "Capture Source",
  581. .type = SB_MIX_CAPTURE_DT019X
  582. };
  583. static struct sbmix_elem *snd_dt019x_controls[] = {
  584. &snd_dt019x_ctl_master_play_vol,
  585. &snd_dt019x_ctl_pcm_play_vol,
  586. &snd_dt019x_ctl_synth_play_vol,
  587. &snd_dt019x_ctl_cd_play_vol,
  588. &snd_dt019x_ctl_mic_play_vol,
  589. &snd_dt019x_ctl_pc_speaker_vol,
  590. &snd_dt019x_ctl_line_play_vol,
  591. &snd_sb16_ctl_mic_play_switch,
  592. &snd_sb16_ctl_cd_play_switch,
  593. &snd_sb16_ctl_line_play_switch,
  594. &snd_dt019x_ctl_pcm_play_switch,
  595. &snd_dt019x_ctl_synth_play_switch,
  596. &snd_dt019x_ctl_capture_source
  597. };
  598. static unsigned char snd_dt019x_init_values[][2] = {
  599. { SB_DT019X_MASTER_DEV, 0 },
  600. { SB_DT019X_PCM_DEV, 0 },
  601. { SB_DT019X_SYNTH_DEV, 0 },
  602. { SB_DT019X_CD_DEV, 0 },
  603. { SB_DT019X_MIC_DEV, 0 }, /* Includes PC-speaker in high nibble */
  604. { SB_DT019X_LINE_DEV, 0 },
  605. { SB_DSP4_OUTPUT_SW, 0 },
  606. { SB_DT019X_OUTPUT_SW2, 0 },
  607. { SB_DT019X_CAPTURE_SW, 0x06 },
  608. };
  609. /*
  610. * ALS4000 specific mixer elements
  611. */
  612. /* FIXME: SB_ALS4000_MONO_IO_CTRL needs output select ctrl! */
  613. static struct sbmix_elem snd_als4000_ctl_master_mono_playback_switch =
  614. SB_SINGLE("Master Mono Playback Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1);
  615. static struct sbmix_elem snd_als4000_ctl_master_mono_capture_route =
  616. SB_SINGLE("Master Mono Capture Route", SB_ALS4000_MONO_IO_CTRL, 6, 0x03);
  617. /* FIXME: mono playback switch also available on DT019X? */
  618. static struct sbmix_elem snd_als4000_ctl_mono_playback_switch =
  619. SB_SINGLE("Mono Playback Switch", SB_DT019X_OUTPUT_SW2, 0, 1);
  620. static struct sbmix_elem snd_als4000_ctl_mic_20db_boost =
  621. SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03);
  622. static struct sbmix_elem snd_als4000_ctl_mixer_loopback =
  623. SB_SINGLE("Analog Loopback", SB_ALS4000_MIC_IN_GAIN, 7, 0x01);
  624. /* FIXME: functionality of 3D controls might be swapped, I didn't find
  625. * a description of how to identify what is supposed to be what */
  626. static struct sbmix_elem snd_als4000_3d_control_switch =
  627. SB_SINGLE("3D Control - Switch", SB_ALS4000_3D_SND_FX, 6, 0x01);
  628. static struct sbmix_elem snd_als4000_3d_control_ratio =
  629. SB_SINGLE("3D Control - Level", SB_ALS4000_3D_SND_FX, 0, 0x07);
  630. static struct sbmix_elem snd_als4000_3d_control_freq =
  631. /* FIXME: maybe there's actually some standard 3D ctrl name for it?? */
  632. SB_SINGLE("3D Control - Freq", SB_ALS4000_3D_SND_FX, 4, 0x03);
  633. static struct sbmix_elem snd_als4000_3d_control_delay =
  634. /* FIXME: ALS4000a.pdf mentions BBD (Bucket Brigade Device) time delay,
  635. * but what ALSA 3D attribute is that actually? "Center", "Depth",
  636. * "Wide" or "Space" or even "Level"? Assuming "Wide" for now... */
  637. SB_SINGLE("3D Control - Wide", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f);
  638. static struct sbmix_elem snd_als4000_3d_control_poweroff_switch =
  639. SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01);
  640. #ifdef NOT_AVAILABLE
  641. static struct sbmix_elem snd_als4000_ctl_fmdac =
  642. SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01);
  643. static struct sbmix_elem snd_als4000_ctl_qsound =
  644. SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND, 1, 0x1f);
  645. #endif
  646. static struct sbmix_elem *snd_als4000_controls[] = {
  647. &snd_sb16_ctl_master_play_vol,
  648. &snd_dt019x_ctl_pcm_play_switch,
  649. &snd_sb16_ctl_pcm_play_vol,
  650. &snd_sb16_ctl_synth_capture_route,
  651. &snd_dt019x_ctl_synth_play_switch,
  652. &snd_sb16_ctl_synth_play_vol,
  653. &snd_sb16_ctl_cd_capture_route,
  654. &snd_sb16_ctl_cd_play_switch,
  655. &snd_sb16_ctl_cd_play_vol,
  656. &snd_sb16_ctl_line_capture_route,
  657. &snd_sb16_ctl_line_play_switch,
  658. &snd_sb16_ctl_line_play_vol,
  659. &snd_sb16_ctl_mic_capture_route,
  660. &snd_als4000_ctl_mic_20db_boost,
  661. &snd_sb16_ctl_auto_mic_gain,
  662. &snd_sb16_ctl_mic_play_switch,
  663. &snd_sb16_ctl_mic_play_vol,
  664. &snd_sb16_ctl_pc_speaker_vol,
  665. &snd_sb16_ctl_capture_vol,
  666. &snd_sb16_ctl_play_vol,
  667. &snd_als4000_ctl_master_mono_playback_switch,
  668. &snd_als4000_ctl_master_mono_capture_route,
  669. &snd_als4000_ctl_mono_playback_switch,
  670. &snd_als4000_ctl_mixer_loopback,
  671. &snd_als4000_3d_control_switch,
  672. &snd_als4000_3d_control_ratio,
  673. &snd_als4000_3d_control_freq,
  674. &snd_als4000_3d_control_delay,
  675. &snd_als4000_3d_control_poweroff_switch,
  676. #ifdef NOT_AVAILABLE
  677. &snd_als4000_ctl_fmdac,
  678. &snd_als4000_ctl_qsound,
  679. #endif
  680. };
  681. static unsigned char snd_als4000_init_values[][2] = {
  682. { SB_DSP4_MASTER_DEV + 0, 0 },
  683. { SB_DSP4_MASTER_DEV + 1, 0 },
  684. { SB_DSP4_PCM_DEV + 0, 0 },
  685. { SB_DSP4_PCM_DEV + 1, 0 },
  686. { SB_DSP4_SYNTH_DEV + 0, 0 },
  687. { SB_DSP4_SYNTH_DEV + 1, 0 },
  688. { SB_DSP4_SPEAKER_DEV, 0 },
  689. { SB_DSP4_OUTPUT_SW, 0 },
  690. { SB_DSP4_INPUT_LEFT, 0 },
  691. { SB_DSP4_INPUT_RIGHT, 0 },
  692. { SB_DT019X_OUTPUT_SW2, 0 },
  693. { SB_ALS4000_MIC_IN_GAIN, 0 },
  694. };
  695. /*
  696. */
  697. static int snd_sbmixer_init(struct snd_sb *chip,
  698. struct sbmix_elem **controls,
  699. int controls_count,
  700. unsigned char map[][2],
  701. int map_count,
  702. char *name)
  703. {
  704. unsigned long flags;
  705. struct snd_card *card = chip->card;
  706. int idx, err;
  707. /* mixer reset */
  708. spin_lock_irqsave(&chip->mixer_lock, flags);
  709. snd_sbmixer_write(chip, 0x00, 0x00);
  710. spin_unlock_irqrestore(&chip->mixer_lock, flags);
  711. /* mute and zero volume channels */
  712. for (idx = 0; idx < map_count; idx++) {
  713. spin_lock_irqsave(&chip->mixer_lock, flags);
  714. snd_sbmixer_write(chip, map[idx][0], map[idx][1]);
  715. spin_unlock_irqrestore(&chip->mixer_lock, flags);
  716. }
  717. for (idx = 0; idx < controls_count; idx++) {
  718. if ((err = snd_sbmixer_add_ctl_elem(chip, controls[idx])) < 0)
  719. return err;
  720. }
  721. snd_component_add(card, name);
  722. strcpy(card->mixername, name);
  723. return 0;
  724. }
  725. int snd_sbmixer_new(struct snd_sb *chip)
  726. {
  727. struct snd_card *card;
  728. int err;
  729. if (snd_BUG_ON(!chip || !chip->card))
  730. return -EINVAL;
  731. card = chip->card;
  732. switch (chip->hardware) {
  733. case SB_HW_10:
  734. return 0; /* no mixer chip on SB1.x */
  735. case SB_HW_20:
  736. case SB_HW_201:
  737. if ((err = snd_sbmixer_init(chip,
  738. snd_sb20_controls,
  739. ARRAY_SIZE(snd_sb20_controls),
  740. snd_sb20_init_values,
  741. ARRAY_SIZE(snd_sb20_init_values),
  742. "CTL1335")) < 0)
  743. return err;
  744. break;
  745. case SB_HW_PRO:
  746. if ((err = snd_sbmixer_init(chip,
  747. snd_sbpro_controls,
  748. ARRAY_SIZE(snd_sbpro_controls),
  749. snd_sbpro_init_values,
  750. ARRAY_SIZE(snd_sbpro_init_values),
  751. "CTL1345")) < 0)
  752. return err;
  753. break;
  754. case SB_HW_16:
  755. case SB_HW_ALS100:
  756. case SB_HW_CS5530:
  757. if ((err = snd_sbmixer_init(chip,
  758. snd_sb16_controls,
  759. ARRAY_SIZE(snd_sb16_controls),
  760. snd_sb16_init_values,
  761. ARRAY_SIZE(snd_sb16_init_values),
  762. "CTL1745")) < 0)
  763. return err;
  764. break;
  765. case SB_HW_ALS4000:
  766. if ((err = snd_sbmixer_init(chip,
  767. snd_als4000_controls,
  768. ARRAY_SIZE(snd_als4000_controls),
  769. snd_als4000_init_values,
  770. ARRAY_SIZE(snd_als4000_init_values),
  771. "ALS4000")) < 0)
  772. return err;
  773. break;
  774. case SB_HW_DT019X:
  775. if ((err = snd_sbmixer_init(chip,
  776. snd_dt019x_controls,
  777. ARRAY_SIZE(snd_dt019x_controls),
  778. snd_dt019x_init_values,
  779. ARRAY_SIZE(snd_dt019x_init_values),
  780. "DT019X")) < 0)
  781. break;
  782. default:
  783. strcpy(card->mixername, "???");
  784. }
  785. return 0;
  786. }
  787. #ifdef CONFIG_PM
  788. static unsigned char sb20_saved_regs[] = {
  789. SB_DSP20_MASTER_DEV,
  790. SB_DSP20_PCM_DEV,
  791. SB_DSP20_FM_DEV,
  792. SB_DSP20_CD_DEV,
  793. };
  794. static unsigned char sbpro_saved_regs[] = {
  795. SB_DSP_MASTER_DEV,
  796. SB_DSP_PCM_DEV,
  797. SB_DSP_PLAYBACK_FILT,
  798. SB_DSP_FM_DEV,
  799. SB_DSP_CD_DEV,
  800. SB_DSP_LINE_DEV,
  801. SB_DSP_MIC_DEV,
  802. SB_DSP_CAPTURE_SOURCE,
  803. SB_DSP_CAPTURE_FILT,
  804. };
  805. static unsigned char sb16_saved_regs[] = {
  806. SB_DSP4_MASTER_DEV, SB_DSP4_MASTER_DEV + 1,
  807. SB_DSP4_3DSE,
  808. SB_DSP4_BASS_DEV, SB_DSP4_BASS_DEV + 1,
  809. SB_DSP4_TREBLE_DEV, SB_DSP4_TREBLE_DEV + 1,
  810. SB_DSP4_PCM_DEV, SB_DSP4_PCM_DEV + 1,
  811. SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT,
  812. SB_DSP4_SYNTH_DEV, SB_DSP4_SYNTH_DEV + 1,
  813. SB_DSP4_OUTPUT_SW,
  814. SB_DSP4_CD_DEV, SB_DSP4_CD_DEV + 1,
  815. SB_DSP4_LINE_DEV, SB_DSP4_LINE_DEV + 1,
  816. SB_DSP4_MIC_DEV,
  817. SB_DSP4_SPEAKER_DEV,
  818. SB_DSP4_IGAIN_DEV, SB_DSP4_IGAIN_DEV + 1,
  819. SB_DSP4_OGAIN_DEV, SB_DSP4_OGAIN_DEV + 1,
  820. SB_DSP4_MIC_AGC
  821. };
  822. static unsigned char dt019x_saved_regs[] = {
  823. SB_DT019X_MASTER_DEV,
  824. SB_DT019X_PCM_DEV,
  825. SB_DT019X_SYNTH_DEV,
  826. SB_DT019X_CD_DEV,
  827. SB_DT019X_MIC_DEV,
  828. SB_DT019X_SPKR_DEV,
  829. SB_DT019X_LINE_DEV,
  830. SB_DSP4_OUTPUT_SW,
  831. SB_DT019X_OUTPUT_SW2,
  832. SB_DT019X_CAPTURE_SW,
  833. };
  834. static unsigned char als4000_saved_regs[] = {
  835. SB_DSP4_MASTER_DEV, SB_DSP4_MASTER_DEV + 1,
  836. SB_DSP4_OUTPUT_SW,
  837. SB_DSP4_PCM_DEV, SB_DSP4_PCM_DEV + 1,
  838. SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT,
  839. SB_DSP4_SYNTH_DEV, SB_DSP4_SYNTH_DEV + 1,
  840. SB_DSP4_CD_DEV, SB_DSP4_CD_DEV + 1,
  841. SB_DSP4_MIC_AGC,
  842. SB_DSP4_MIC_DEV,
  843. SB_DSP4_SPEAKER_DEV,
  844. SB_DSP4_IGAIN_DEV, SB_DSP4_IGAIN_DEV + 1,
  845. SB_DSP4_OGAIN_DEV, SB_DSP4_OGAIN_DEV + 1,
  846. SB_DT019X_OUTPUT_SW2,
  847. SB_ALS4000_MONO_IO_CTRL,
  848. SB_ALS4000_MIC_IN_GAIN,
  849. SB_ALS4000_3D_SND_FX,
  850. SB_ALS4000_3D_TIME_DELAY,
  851. };
  852. static void save_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs)
  853. {
  854. unsigned char *val = chip->saved_regs;
  855. if (snd_BUG_ON(num_regs > ARRAY_SIZE(chip->saved_regs)))
  856. return;
  857. for (; num_regs; num_regs--)
  858. *val++ = snd_sbmixer_read(chip, *regs++);
  859. }
  860. static void restore_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs)
  861. {
  862. unsigned char *val = chip->saved_regs;
  863. if (snd_BUG_ON(num_regs > ARRAY_SIZE(chip->saved_regs)))
  864. return;
  865. for (; num_regs; num_regs--)
  866. snd_sbmixer_write(chip, *regs++, *val++);
  867. }
  868. void snd_sbmixer_suspend(struct snd_sb *chip)
  869. {
  870. switch (chip->hardware) {
  871. case SB_HW_20:
  872. case SB_HW_201:
  873. save_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs));
  874. break;
  875. case SB_HW_PRO:
  876. save_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs));
  877. break;
  878. case SB_HW_16:
  879. case SB_HW_ALS100:
  880. case SB_HW_CS5530:
  881. save_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs));
  882. break;
  883. case SB_HW_ALS4000:
  884. save_mixer(chip, als4000_saved_regs, ARRAY_SIZE(als4000_saved_regs));
  885. break;
  886. case SB_HW_DT019X:
  887. save_mixer(chip, dt019x_saved_regs, ARRAY_SIZE(dt019x_saved_regs));
  888. break;
  889. default:
  890. break;
  891. }
  892. }
  893. void snd_sbmixer_resume(struct snd_sb *chip)
  894. {
  895. switch (chip->hardware) {
  896. case SB_HW_20:
  897. case SB_HW_201:
  898. restore_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs));
  899. break;
  900. case SB_HW_PRO:
  901. restore_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs));
  902. break;
  903. case SB_HW_16:
  904. case SB_HW_ALS100:
  905. case SB_HW_CS5530:
  906. restore_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs));
  907. break;
  908. case SB_HW_ALS4000:
  909. restore_mixer(chip, als4000_saved_regs, ARRAY_SIZE(als4000_saved_regs));
  910. break;
  911. case SB_HW_DT019X:
  912. restore_mixer(chip, dt019x_saved_regs, ARRAY_SIZE(dt019x_saved_regs));
  913. break;
  914. default:
  915. break;
  916. }
  917. }
  918. #endif