sb_mixer.c 31 KB

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