sb_mixer.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990
  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. return err;
  415. return 0;
  416. }
  417. /*
  418. * SB 2.0 specific mixer elements
  419. */
  420. static struct sbmix_elem snd_sb20_ctl_master_play_vol =
  421. SB_SINGLE("Master Playback Volume", SB_DSP20_MASTER_DEV, 1, 7);
  422. static struct sbmix_elem snd_sb20_ctl_pcm_play_vol =
  423. SB_SINGLE("PCM Playback Volume", SB_DSP20_PCM_DEV, 1, 3);
  424. static struct sbmix_elem snd_sb20_ctl_synth_play_vol =
  425. SB_SINGLE("Synth Playback Volume", SB_DSP20_FM_DEV, 1, 7);
  426. static struct sbmix_elem snd_sb20_ctl_cd_play_vol =
  427. SB_SINGLE("CD Playback Volume", SB_DSP20_CD_DEV, 1, 7);
  428. static struct sbmix_elem *snd_sb20_controls[] = {
  429. &snd_sb20_ctl_master_play_vol,
  430. &snd_sb20_ctl_pcm_play_vol,
  431. &snd_sb20_ctl_synth_play_vol,
  432. &snd_sb20_ctl_cd_play_vol
  433. };
  434. static unsigned char snd_sb20_init_values[][2] = {
  435. { SB_DSP20_MASTER_DEV, 0 },
  436. { SB_DSP20_FM_DEV, 0 },
  437. };
  438. /*
  439. * SB Pro specific mixer elements
  440. */
  441. static struct sbmix_elem snd_sbpro_ctl_master_play_vol =
  442. SB_DOUBLE("Master Playback Volume", SB_DSP_MASTER_DEV, SB_DSP_MASTER_DEV, 5, 1, 7);
  443. static struct sbmix_elem snd_sbpro_ctl_pcm_play_vol =
  444. SB_DOUBLE("PCM Playback Volume", SB_DSP_PCM_DEV, SB_DSP_PCM_DEV, 5, 1, 7);
  445. static struct sbmix_elem snd_sbpro_ctl_pcm_play_filter =
  446. SB_SINGLE("PCM Playback Filter", SB_DSP_PLAYBACK_FILT, 5, 1);
  447. static struct sbmix_elem snd_sbpro_ctl_synth_play_vol =
  448. SB_DOUBLE("Synth Playback Volume", SB_DSP_FM_DEV, SB_DSP_FM_DEV, 5, 1, 7);
  449. static struct sbmix_elem snd_sbpro_ctl_cd_play_vol =
  450. SB_DOUBLE("CD Playback Volume", SB_DSP_CD_DEV, SB_DSP_CD_DEV, 5, 1, 7);
  451. static struct sbmix_elem snd_sbpro_ctl_line_play_vol =
  452. SB_DOUBLE("Line Playback Volume", SB_DSP_LINE_DEV, SB_DSP_LINE_DEV, 5, 1, 7);
  453. static struct sbmix_elem snd_sbpro_ctl_mic_play_vol =
  454. SB_SINGLE("Mic Playback Volume", SB_DSP_MIC_DEV, 1, 3);
  455. static struct sbmix_elem snd_sbpro_ctl_capture_source =
  456. {
  457. .name = "Capture Source",
  458. .type = SB_MIX_CAPTURE_PRO
  459. };
  460. static struct sbmix_elem snd_sbpro_ctl_capture_filter =
  461. SB_SINGLE("Capture Filter", SB_DSP_CAPTURE_FILT, 5, 1);
  462. static struct sbmix_elem snd_sbpro_ctl_capture_low_filter =
  463. SB_SINGLE("Capture Low-Pass Filter", SB_DSP_CAPTURE_FILT, 3, 1);
  464. static struct sbmix_elem *snd_sbpro_controls[] = {
  465. &snd_sbpro_ctl_master_play_vol,
  466. &snd_sbpro_ctl_pcm_play_vol,
  467. &snd_sbpro_ctl_pcm_play_filter,
  468. &snd_sbpro_ctl_synth_play_vol,
  469. &snd_sbpro_ctl_cd_play_vol,
  470. &snd_sbpro_ctl_line_play_vol,
  471. &snd_sbpro_ctl_mic_play_vol,
  472. &snd_sbpro_ctl_capture_source,
  473. &snd_sbpro_ctl_capture_filter,
  474. &snd_sbpro_ctl_capture_low_filter
  475. };
  476. static unsigned char snd_sbpro_init_values[][2] = {
  477. { SB_DSP_MASTER_DEV, 0 },
  478. { SB_DSP_PCM_DEV, 0 },
  479. { SB_DSP_FM_DEV, 0 },
  480. };
  481. /*
  482. * SB16 specific mixer elements
  483. */
  484. static struct sbmix_elem snd_sb16_ctl_master_play_vol =
  485. SB_DOUBLE("Master Playback Volume", SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31);
  486. static struct sbmix_elem snd_sb16_ctl_3d_enhance_switch =
  487. SB_SINGLE("3D Enhancement Switch", SB_DSP4_3DSE, 0, 1);
  488. static struct sbmix_elem snd_sb16_ctl_tone_bass =
  489. SB_DOUBLE("Tone Control - Bass", SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15);
  490. static struct sbmix_elem snd_sb16_ctl_tone_treble =
  491. SB_DOUBLE("Tone Control - Treble", SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15);
  492. static struct sbmix_elem snd_sb16_ctl_pcm_play_vol =
  493. SB_DOUBLE("PCM Playback Volume", SB_DSP4_PCM_DEV, (SB_DSP4_PCM_DEV + 1), 3, 3, 31);
  494. static struct sbmix_elem snd_sb16_ctl_synth_capture_route =
  495. SB16_INPUT_SW("Synth Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 6, 5);
  496. static struct sbmix_elem snd_sb16_ctl_synth_play_vol =
  497. SB_DOUBLE("Synth Playback Volume", SB_DSP4_SYNTH_DEV, (SB_DSP4_SYNTH_DEV + 1), 3, 3, 31);
  498. static struct sbmix_elem snd_sb16_ctl_cd_capture_route =
  499. SB16_INPUT_SW("CD Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 2, 1);
  500. static struct sbmix_elem snd_sb16_ctl_cd_play_switch =
  501. SB_DOUBLE("CD Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1);
  502. static struct sbmix_elem snd_sb16_ctl_cd_play_vol =
  503. SB_DOUBLE("CD Playback Volume", SB_DSP4_CD_DEV, (SB_DSP4_CD_DEV + 1), 3, 3, 31);
  504. static struct sbmix_elem snd_sb16_ctl_line_capture_route =
  505. SB16_INPUT_SW("Line Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 4, 3);
  506. static struct sbmix_elem snd_sb16_ctl_line_play_switch =
  507. SB_DOUBLE("Line Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1);
  508. static struct sbmix_elem snd_sb16_ctl_line_play_vol =
  509. SB_DOUBLE("Line Playback Volume", SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31);
  510. static struct sbmix_elem snd_sb16_ctl_mic_capture_route =
  511. SB16_INPUT_SW("Mic Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0);
  512. static struct sbmix_elem snd_sb16_ctl_mic_play_switch =
  513. SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1);
  514. static struct sbmix_elem snd_sb16_ctl_mic_play_vol =
  515. SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31);
  516. static struct sbmix_elem snd_sb16_ctl_pc_speaker_vol =
  517. SB_SINGLE("PC Speaker Volume", SB_DSP4_SPEAKER_DEV, 6, 3);
  518. static struct sbmix_elem snd_sb16_ctl_capture_vol =
  519. SB_DOUBLE("Capture Volume", SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3);
  520. static struct sbmix_elem snd_sb16_ctl_play_vol =
  521. SB_DOUBLE("Playback Volume", SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3);
  522. static struct sbmix_elem snd_sb16_ctl_auto_mic_gain =
  523. SB_SINGLE("Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1);
  524. static struct sbmix_elem *snd_sb16_controls[] = {
  525. &snd_sb16_ctl_master_play_vol,
  526. &snd_sb16_ctl_3d_enhance_switch,
  527. &snd_sb16_ctl_tone_bass,
  528. &snd_sb16_ctl_tone_treble,
  529. &snd_sb16_ctl_pcm_play_vol,
  530. &snd_sb16_ctl_synth_capture_route,
  531. &snd_sb16_ctl_synth_play_vol,
  532. &snd_sb16_ctl_cd_capture_route,
  533. &snd_sb16_ctl_cd_play_switch,
  534. &snd_sb16_ctl_cd_play_vol,
  535. &snd_sb16_ctl_line_capture_route,
  536. &snd_sb16_ctl_line_play_switch,
  537. &snd_sb16_ctl_line_play_vol,
  538. &snd_sb16_ctl_mic_capture_route,
  539. &snd_sb16_ctl_mic_play_switch,
  540. &snd_sb16_ctl_mic_play_vol,
  541. &snd_sb16_ctl_pc_speaker_vol,
  542. &snd_sb16_ctl_capture_vol,
  543. &snd_sb16_ctl_play_vol,
  544. &snd_sb16_ctl_auto_mic_gain
  545. };
  546. static unsigned char snd_sb16_init_values[][2] = {
  547. { SB_DSP4_MASTER_DEV + 0, 0 },
  548. { SB_DSP4_MASTER_DEV + 1, 0 },
  549. { SB_DSP4_PCM_DEV + 0, 0 },
  550. { SB_DSP4_PCM_DEV + 1, 0 },
  551. { SB_DSP4_SYNTH_DEV + 0, 0 },
  552. { SB_DSP4_SYNTH_DEV + 1, 0 },
  553. { SB_DSP4_INPUT_LEFT, 0 },
  554. { SB_DSP4_INPUT_RIGHT, 0 },
  555. { SB_DSP4_OUTPUT_SW, 0 },
  556. { SB_DSP4_SPEAKER_DEV, 0 },
  557. };
  558. /*
  559. * DT019x specific mixer elements
  560. */
  561. static struct sbmix_elem snd_dt019x_ctl_master_play_vol =
  562. SB_DOUBLE("Master Playback Volume", SB_DT019X_MASTER_DEV, SB_DT019X_MASTER_DEV, 4,0, 15);
  563. static struct sbmix_elem snd_dt019x_ctl_pcm_play_vol =
  564. SB_DOUBLE("PCM Playback Volume", SB_DT019X_PCM_DEV, SB_DT019X_PCM_DEV, 4,0, 15);
  565. static struct sbmix_elem snd_dt019x_ctl_synth_play_vol =
  566. SB_DOUBLE("Synth Playback Volume", SB_DT019X_SYNTH_DEV, SB_DT019X_SYNTH_DEV, 4,0, 15);
  567. static struct sbmix_elem snd_dt019x_ctl_cd_play_vol =
  568. SB_DOUBLE("CD Playback Volume", SB_DT019X_CD_DEV, SB_DT019X_CD_DEV, 4,0, 15);
  569. static struct sbmix_elem snd_dt019x_ctl_mic_play_vol =
  570. SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7);
  571. static struct sbmix_elem snd_dt019x_ctl_pc_speaker_vol =
  572. SB_SINGLE("PC Speaker Volume", SB_DT019X_SPKR_DEV, 0, 7);
  573. static struct sbmix_elem snd_dt019x_ctl_line_play_vol =
  574. SB_DOUBLE("Line Playback Volume", SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4,0, 15);
  575. static struct sbmix_elem snd_dt019x_ctl_pcm_play_switch =
  576. SB_DOUBLE("PCM Playback Switch", SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2,1, 1);
  577. static struct sbmix_elem snd_dt019x_ctl_synth_play_switch =
  578. SB_DOUBLE("Synth Playback Switch", SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4,3, 1);
  579. static struct sbmix_elem snd_dt019x_ctl_capture_source =
  580. {
  581. .name = "Capture Source",
  582. .type = SB_MIX_CAPTURE_DT019X
  583. };
  584. static struct sbmix_elem *snd_dt019x_controls[] = {
  585. &snd_dt019x_ctl_master_play_vol,
  586. &snd_dt019x_ctl_pcm_play_vol,
  587. &snd_dt019x_ctl_synth_play_vol,
  588. &snd_dt019x_ctl_cd_play_vol,
  589. &snd_dt019x_ctl_mic_play_vol,
  590. &snd_dt019x_ctl_pc_speaker_vol,
  591. &snd_dt019x_ctl_line_play_vol,
  592. &snd_sb16_ctl_mic_play_switch,
  593. &snd_sb16_ctl_cd_play_switch,
  594. &snd_sb16_ctl_line_play_switch,
  595. &snd_dt019x_ctl_pcm_play_switch,
  596. &snd_dt019x_ctl_synth_play_switch,
  597. &snd_dt019x_ctl_capture_source
  598. };
  599. static unsigned char snd_dt019x_init_values[][2] = {
  600. { SB_DT019X_MASTER_DEV, 0 },
  601. { SB_DT019X_PCM_DEV, 0 },
  602. { SB_DT019X_SYNTH_DEV, 0 },
  603. { SB_DT019X_CD_DEV, 0 },
  604. { SB_DT019X_MIC_DEV, 0 }, /* Includes PC-speaker in high nibble */
  605. { SB_DT019X_LINE_DEV, 0 },
  606. { SB_DSP4_OUTPUT_SW, 0 },
  607. { SB_DT019X_OUTPUT_SW2, 0 },
  608. { SB_DT019X_CAPTURE_SW, 0x06 },
  609. };
  610. /*
  611. * ALS4000 specific mixer elements
  612. */
  613. /* FIXME: SB_ALS4000_MONO_IO_CTRL needs output select ctrl! */
  614. static struct sbmix_elem snd_als4000_ctl_master_mono_playback_switch =
  615. SB_SINGLE("Master Mono Playback Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1);
  616. static struct sbmix_elem snd_als4000_ctl_master_mono_capture_route =
  617. SB_SINGLE("Master Mono Capture Route", SB_ALS4000_MONO_IO_CTRL, 6, 0x03);
  618. /* FIXME: mono playback switch also available on DT019X? */
  619. static struct sbmix_elem snd_als4000_ctl_mono_playback_switch =
  620. SB_SINGLE("Mono Playback Switch", SB_DT019X_OUTPUT_SW2, 0, 1);
  621. static struct sbmix_elem snd_als4000_ctl_mic_20db_boost =
  622. SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03);
  623. static struct sbmix_elem snd_als4000_ctl_mixer_loopback =
  624. SB_SINGLE("Analog Loopback", SB_ALS4000_MIC_IN_GAIN, 7, 0x01);
  625. /* FIXME: functionality of 3D controls might be swapped, I didn't find
  626. * a description of how to identify what is supposed to be what */
  627. static struct sbmix_elem snd_als4000_3d_control_switch =
  628. SB_SINGLE("3D Control - Switch", SB_ALS4000_3D_SND_FX, 6, 0x01);
  629. static struct sbmix_elem snd_als4000_3d_control_ratio =
  630. SB_SINGLE("3D Control - Level", SB_ALS4000_3D_SND_FX, 0, 0x07);
  631. static struct sbmix_elem snd_als4000_3d_control_freq =
  632. /* FIXME: maybe there's actually some standard 3D ctrl name for it?? */
  633. SB_SINGLE("3D Control - Freq", SB_ALS4000_3D_SND_FX, 4, 0x03);
  634. static struct sbmix_elem snd_als4000_3d_control_delay =
  635. /* FIXME: ALS4000a.pdf mentions BBD (Bucket Brigade Device) time delay,
  636. * but what ALSA 3D attribute is that actually? "Center", "Depth",
  637. * "Wide" or "Space" or even "Level"? Assuming "Wide" for now... */
  638. SB_SINGLE("3D Control - Wide", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f);
  639. static struct sbmix_elem snd_als4000_3d_control_poweroff_switch =
  640. SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01);
  641. #ifdef NOT_AVAILABLE
  642. static struct sbmix_elem snd_als4000_ctl_fmdac =
  643. SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01);
  644. static struct sbmix_elem snd_als4000_ctl_qsound =
  645. SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND, 1, 0x1f);
  646. #endif
  647. static struct sbmix_elem *snd_als4000_controls[] = {
  648. &snd_sb16_ctl_master_play_vol,
  649. &snd_dt019x_ctl_pcm_play_switch,
  650. &snd_sb16_ctl_pcm_play_vol,
  651. &snd_sb16_ctl_synth_capture_route,
  652. &snd_dt019x_ctl_synth_play_switch,
  653. &snd_sb16_ctl_synth_play_vol,
  654. &snd_sb16_ctl_cd_capture_route,
  655. &snd_sb16_ctl_cd_play_switch,
  656. &snd_sb16_ctl_cd_play_vol,
  657. &snd_sb16_ctl_line_capture_route,
  658. &snd_sb16_ctl_line_play_switch,
  659. &snd_sb16_ctl_line_play_vol,
  660. &snd_sb16_ctl_mic_capture_route,
  661. &snd_als4000_ctl_mic_20db_boost,
  662. &snd_sb16_ctl_auto_mic_gain,
  663. &snd_sb16_ctl_mic_play_switch,
  664. &snd_sb16_ctl_mic_play_vol,
  665. &snd_sb16_ctl_pc_speaker_vol,
  666. &snd_sb16_ctl_capture_vol,
  667. &snd_sb16_ctl_play_vol,
  668. &snd_als4000_ctl_master_mono_playback_switch,
  669. &snd_als4000_ctl_master_mono_capture_route,
  670. &snd_als4000_ctl_mono_playback_switch,
  671. &snd_als4000_ctl_mixer_loopback,
  672. &snd_als4000_3d_control_switch,
  673. &snd_als4000_3d_control_ratio,
  674. &snd_als4000_3d_control_freq,
  675. &snd_als4000_3d_control_delay,
  676. &snd_als4000_3d_control_poweroff_switch,
  677. #ifdef NOT_AVAILABLE
  678. &snd_als4000_ctl_fmdac,
  679. &snd_als4000_ctl_qsound,
  680. #endif
  681. };
  682. static unsigned char snd_als4000_init_values[][2] = {
  683. { SB_DSP4_MASTER_DEV + 0, 0 },
  684. { SB_DSP4_MASTER_DEV + 1, 0 },
  685. { SB_DSP4_PCM_DEV + 0, 0 },
  686. { SB_DSP4_PCM_DEV + 1, 0 },
  687. { SB_DSP4_SYNTH_DEV + 0, 0 },
  688. { SB_DSP4_SYNTH_DEV + 1, 0 },
  689. { SB_DSP4_SPEAKER_DEV, 0 },
  690. { SB_DSP4_OUTPUT_SW, 0 },
  691. { SB_DSP4_INPUT_LEFT, 0 },
  692. { SB_DSP4_INPUT_RIGHT, 0 },
  693. { SB_DT019X_OUTPUT_SW2, 0 },
  694. { SB_ALS4000_MIC_IN_GAIN, 0 },
  695. };
  696. /*
  697. */
  698. static int snd_sbmixer_init(struct snd_sb *chip,
  699. struct sbmix_elem **controls,
  700. int controls_count,
  701. unsigned char map[][2],
  702. int map_count,
  703. char *name)
  704. {
  705. unsigned long flags;
  706. struct snd_card *card = chip->card;
  707. int idx, err;
  708. /* mixer reset */
  709. spin_lock_irqsave(&chip->mixer_lock, flags);
  710. snd_sbmixer_write(chip, 0x00, 0x00);
  711. spin_unlock_irqrestore(&chip->mixer_lock, flags);
  712. /* mute and zero volume channels */
  713. for (idx = 0; idx < map_count; idx++) {
  714. spin_lock_irqsave(&chip->mixer_lock, flags);
  715. snd_sbmixer_write(chip, map[idx][0], map[idx][1]);
  716. spin_unlock_irqrestore(&chip->mixer_lock, flags);
  717. }
  718. for (idx = 0; idx < controls_count; idx++) {
  719. if ((err = snd_sbmixer_add_ctl_elem(chip, controls[idx])) < 0)
  720. return err;
  721. }
  722. snd_component_add(card, name);
  723. strcpy(card->mixername, name);
  724. return 0;
  725. }
  726. int snd_sbmixer_new(struct snd_sb *chip)
  727. {
  728. struct snd_card *card;
  729. int err;
  730. snd_assert(chip != NULL && chip->card != NULL, 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. if ((err = snd_sbmixer_init(chip,
  757. snd_sb16_controls,
  758. ARRAY_SIZE(snd_sb16_controls),
  759. snd_sb16_init_values,
  760. ARRAY_SIZE(snd_sb16_init_values),
  761. "CTL1745")) < 0)
  762. return err;
  763. break;
  764. case SB_HW_ALS4000:
  765. if ((err = snd_sbmixer_init(chip,
  766. snd_als4000_controls,
  767. ARRAY_SIZE(snd_als4000_controls),
  768. snd_als4000_init_values,
  769. ARRAY_SIZE(snd_als4000_init_values),
  770. "ALS4000")) < 0)
  771. return err;
  772. break;
  773. case SB_HW_DT019X:
  774. if ((err = snd_sbmixer_init(chip,
  775. snd_dt019x_controls,
  776. ARRAY_SIZE(snd_dt019x_controls),
  777. snd_dt019x_init_values,
  778. ARRAY_SIZE(snd_dt019x_init_values),
  779. "DT019X")) < 0)
  780. break;
  781. default:
  782. strcpy(card->mixername, "???");
  783. }
  784. return 0;
  785. }
  786. #ifdef CONFIG_PM
  787. static unsigned char sb20_saved_regs[] = {
  788. SB_DSP20_MASTER_DEV,
  789. SB_DSP20_PCM_DEV,
  790. SB_DSP20_FM_DEV,
  791. SB_DSP20_CD_DEV,
  792. };
  793. static unsigned char sbpro_saved_regs[] = {
  794. SB_DSP_MASTER_DEV,
  795. SB_DSP_PCM_DEV,
  796. SB_DSP_PLAYBACK_FILT,
  797. SB_DSP_FM_DEV,
  798. SB_DSP_CD_DEV,
  799. SB_DSP_LINE_DEV,
  800. SB_DSP_MIC_DEV,
  801. SB_DSP_CAPTURE_SOURCE,
  802. SB_DSP_CAPTURE_FILT,
  803. };
  804. static unsigned char sb16_saved_regs[] = {
  805. SB_DSP4_MASTER_DEV, SB_DSP4_MASTER_DEV + 1,
  806. SB_DSP4_3DSE,
  807. SB_DSP4_BASS_DEV, SB_DSP4_BASS_DEV + 1,
  808. SB_DSP4_TREBLE_DEV, SB_DSP4_TREBLE_DEV + 1,
  809. SB_DSP4_PCM_DEV, SB_DSP4_PCM_DEV + 1,
  810. SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT,
  811. SB_DSP4_SYNTH_DEV, SB_DSP4_SYNTH_DEV + 1,
  812. SB_DSP4_OUTPUT_SW,
  813. SB_DSP4_CD_DEV, SB_DSP4_CD_DEV + 1,
  814. SB_DSP4_LINE_DEV, SB_DSP4_LINE_DEV + 1,
  815. SB_DSP4_MIC_DEV,
  816. SB_DSP4_SPEAKER_DEV,
  817. SB_DSP4_IGAIN_DEV, SB_DSP4_IGAIN_DEV + 1,
  818. SB_DSP4_OGAIN_DEV, SB_DSP4_OGAIN_DEV + 1,
  819. SB_DSP4_MIC_AGC
  820. };
  821. static unsigned char dt019x_saved_regs[] = {
  822. SB_DT019X_MASTER_DEV,
  823. SB_DT019X_PCM_DEV,
  824. SB_DT019X_SYNTH_DEV,
  825. SB_DT019X_CD_DEV,
  826. SB_DT019X_MIC_DEV,
  827. SB_DT019X_SPKR_DEV,
  828. SB_DT019X_LINE_DEV,
  829. SB_DSP4_OUTPUT_SW,
  830. SB_DT019X_OUTPUT_SW2,
  831. SB_DT019X_CAPTURE_SW,
  832. };
  833. static unsigned char als4000_saved_regs[] = {
  834. SB_DSP4_MASTER_DEV, SB_DSP4_MASTER_DEV + 1,
  835. SB_DSP4_OUTPUT_SW,
  836. SB_DSP4_PCM_DEV, SB_DSP4_PCM_DEV + 1,
  837. SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT,
  838. SB_DSP4_SYNTH_DEV, SB_DSP4_SYNTH_DEV + 1,
  839. SB_DSP4_CD_DEV, SB_DSP4_CD_DEV + 1,
  840. SB_DSP4_MIC_AGC,
  841. SB_DSP4_MIC_DEV,
  842. SB_DSP4_SPEAKER_DEV,
  843. SB_DSP4_IGAIN_DEV, SB_DSP4_IGAIN_DEV + 1,
  844. SB_DSP4_OGAIN_DEV, SB_DSP4_OGAIN_DEV + 1,
  845. SB_DT019X_OUTPUT_SW2,
  846. SB_ALS4000_MONO_IO_CTRL,
  847. SB_ALS4000_MIC_IN_GAIN,
  848. SB_ALS4000_3D_SND_FX,
  849. SB_ALS4000_3D_TIME_DELAY,
  850. };
  851. static void save_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs)
  852. {
  853. unsigned char *val = chip->saved_regs;
  854. snd_assert(num_regs > ARRAY_SIZE(chip->saved_regs), return);
  855. for (; num_regs; num_regs--)
  856. *val++ = snd_sbmixer_read(chip, *regs++);
  857. }
  858. static void restore_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs)
  859. {
  860. unsigned char *val = chip->saved_regs;
  861. snd_assert(num_regs > ARRAY_SIZE(chip->saved_regs), return);
  862. for (; num_regs; num_regs--)
  863. snd_sbmixer_write(chip, *regs++, *val++);
  864. }
  865. void snd_sbmixer_suspend(struct snd_sb *chip)
  866. {
  867. switch (chip->hardware) {
  868. case SB_HW_20:
  869. case SB_HW_201:
  870. save_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs));
  871. break;
  872. case SB_HW_PRO:
  873. save_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs));
  874. break;
  875. case SB_HW_16:
  876. case SB_HW_ALS100:
  877. save_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs));
  878. break;
  879. case SB_HW_ALS4000:
  880. save_mixer(chip, als4000_saved_regs, ARRAY_SIZE(als4000_saved_regs));
  881. break;
  882. case SB_HW_DT019X:
  883. save_mixer(chip, dt019x_saved_regs, ARRAY_SIZE(dt019x_saved_regs));
  884. break;
  885. default:
  886. break;
  887. }
  888. }
  889. void snd_sbmixer_resume(struct snd_sb *chip)
  890. {
  891. switch (chip->hardware) {
  892. case SB_HW_20:
  893. case SB_HW_201:
  894. restore_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs));
  895. break;
  896. case SB_HW_PRO:
  897. restore_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs));
  898. break;
  899. case SB_HW_16:
  900. case SB_HW_ALS100:
  901. restore_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs));
  902. break;
  903. case SB_HW_ALS4000:
  904. restore_mixer(chip, als4000_saved_regs, ARRAY_SIZE(als4000_saved_regs));
  905. break;
  906. case SB_HW_DT019X:
  907. restore_mixer(chip, dt019x_saved_regs, ARRAY_SIZE(dt019x_saved_regs));
  908. break;
  909. default:
  910. break;
  911. }
  912. }
  913. #endif