sb_mixer.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979
  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 const 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. * ALS4000 mono recording control switch
  246. */
  247. static int snd_als4k_mono_capture_route_info(struct snd_kcontrol *kcontrol,
  248. struct snd_ctl_elem_info *uinfo)
  249. {
  250. static const char *texts[3] = {
  251. "L chan only", "R chan only", "L ch/2 + R ch/2"
  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,
  259. texts[uinfo->value.enumerated.item]);
  260. return 0;
  261. }
  262. static int snd_als4k_mono_capture_route_get(struct snd_kcontrol *kcontrol,
  263. struct snd_ctl_elem_value *ucontrol)
  264. {
  265. struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
  266. unsigned long flags;
  267. unsigned char oval;
  268. spin_lock_irqsave(&sb->mixer_lock, flags);
  269. oval = snd_sbmixer_read(sb, SB_ALS4000_MONO_IO_CTRL);
  270. spin_unlock_irqrestore(&sb->mixer_lock, flags);
  271. oval >>= 6;
  272. if (oval > 2)
  273. oval = 2;
  274. ucontrol->value.enumerated.item[0] = oval;
  275. return 0;
  276. }
  277. static int snd_als4k_mono_capture_route_put(struct snd_kcontrol *kcontrol,
  278. struct snd_ctl_elem_value *ucontrol)
  279. {
  280. struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
  281. unsigned long flags;
  282. int change;
  283. unsigned char nval, oval;
  284. if (ucontrol->value.enumerated.item[0] > 2)
  285. return -EINVAL;
  286. spin_lock_irqsave(&sb->mixer_lock, flags);
  287. oval = snd_sbmixer_read(sb, SB_ALS4000_MONO_IO_CTRL);
  288. nval = (oval & ~(3 << 6))
  289. | (ucontrol->value.enumerated.item[0] << 6);
  290. change = nval != oval;
  291. if (change)
  292. snd_sbmixer_write(sb, SB_ALS4000_MONO_IO_CTRL, nval);
  293. spin_unlock_irqrestore(&sb->mixer_lock, flags);
  294. return change;
  295. }
  296. /*
  297. * SBPRO input multiplexer
  298. */
  299. static int snd_sb8mixer_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
  300. {
  301. static const char *texts[3] = {
  302. "Mic", "CD", "Line"
  303. };
  304. uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
  305. uinfo->count = 1;
  306. uinfo->value.enumerated.items = 3;
  307. if (uinfo->value.enumerated.item > 2)
  308. uinfo->value.enumerated.item = 2;
  309. strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
  310. return 0;
  311. }
  312. static int snd_sb8mixer_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
  313. {
  314. struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
  315. unsigned long flags;
  316. unsigned char oval;
  317. spin_lock_irqsave(&sb->mixer_lock, flags);
  318. oval = snd_sbmixer_read(sb, SB_DSP_CAPTURE_SOURCE);
  319. spin_unlock_irqrestore(&sb->mixer_lock, flags);
  320. switch ((oval >> 0x01) & 0x03) {
  321. case SB_DSP_MIXS_CD:
  322. ucontrol->value.enumerated.item[0] = 1;
  323. break;
  324. case SB_DSP_MIXS_LINE:
  325. ucontrol->value.enumerated.item[0] = 2;
  326. break;
  327. default:
  328. ucontrol->value.enumerated.item[0] = 0;
  329. break;
  330. }
  331. return 0;
  332. }
  333. static int snd_sb8mixer_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
  334. {
  335. struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
  336. unsigned long flags;
  337. int change;
  338. unsigned char nval, oval;
  339. if (ucontrol->value.enumerated.item[0] > 2)
  340. return -EINVAL;
  341. switch (ucontrol->value.enumerated.item[0]) {
  342. case 1:
  343. nval = SB_DSP_MIXS_CD;
  344. break;
  345. case 2:
  346. nval = SB_DSP_MIXS_LINE;
  347. break;
  348. default:
  349. nval = SB_DSP_MIXS_MIC;
  350. }
  351. nval <<= 1;
  352. spin_lock_irqsave(&sb->mixer_lock, flags);
  353. oval = snd_sbmixer_read(sb, SB_DSP_CAPTURE_SOURCE);
  354. nval |= oval & ~0x06;
  355. change = nval != oval;
  356. if (change)
  357. snd_sbmixer_write(sb, SB_DSP_CAPTURE_SOURCE, nval);
  358. spin_unlock_irqrestore(&sb->mixer_lock, flags);
  359. return change;
  360. }
  361. /*
  362. * SB16 input switch
  363. */
  364. static int snd_sb16mixer_info_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
  365. {
  366. uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
  367. uinfo->count = 4;
  368. uinfo->value.integer.min = 0;
  369. uinfo->value.integer.max = 1;
  370. return 0;
  371. }
  372. static int snd_sb16mixer_get_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
  373. {
  374. struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
  375. unsigned long flags;
  376. int reg1 = kcontrol->private_value & 0xff;
  377. int reg2 = (kcontrol->private_value >> 8) & 0xff;
  378. int left_shift = (kcontrol->private_value >> 16) & 0x0f;
  379. int right_shift = (kcontrol->private_value >> 24) & 0x0f;
  380. unsigned char val1, val2;
  381. spin_lock_irqsave(&sb->mixer_lock, flags);
  382. val1 = snd_sbmixer_read(sb, reg1);
  383. val2 = snd_sbmixer_read(sb, reg2);
  384. spin_unlock_irqrestore(&sb->mixer_lock, flags);
  385. ucontrol->value.integer.value[0] = (val1 >> left_shift) & 0x01;
  386. ucontrol->value.integer.value[1] = (val2 >> left_shift) & 0x01;
  387. ucontrol->value.integer.value[2] = (val1 >> right_shift) & 0x01;
  388. ucontrol->value.integer.value[3] = (val2 >> right_shift) & 0x01;
  389. return 0;
  390. }
  391. static int snd_sb16mixer_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
  392. {
  393. struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
  394. unsigned long flags;
  395. int reg1 = kcontrol->private_value & 0xff;
  396. int reg2 = (kcontrol->private_value >> 8) & 0xff;
  397. int left_shift = (kcontrol->private_value >> 16) & 0x0f;
  398. int right_shift = (kcontrol->private_value >> 24) & 0x0f;
  399. int change;
  400. unsigned char val1, val2, oval1, oval2;
  401. spin_lock_irqsave(&sb->mixer_lock, flags);
  402. oval1 = snd_sbmixer_read(sb, reg1);
  403. oval2 = snd_sbmixer_read(sb, reg2);
  404. val1 = oval1 & ~((1 << left_shift) | (1 << right_shift));
  405. val2 = oval2 & ~((1 << left_shift) | (1 << right_shift));
  406. val1 |= (ucontrol->value.integer.value[0] & 1) << left_shift;
  407. val2 |= (ucontrol->value.integer.value[1] & 1) << left_shift;
  408. val1 |= (ucontrol->value.integer.value[2] & 1) << right_shift;
  409. val2 |= (ucontrol->value.integer.value[3] & 1) << right_shift;
  410. change = val1 != oval1 || val2 != oval2;
  411. if (change) {
  412. snd_sbmixer_write(sb, reg1, val1);
  413. snd_sbmixer_write(sb, reg2, val2);
  414. }
  415. spin_unlock_irqrestore(&sb->mixer_lock, flags);
  416. return change;
  417. }
  418. /*
  419. */
  420. /*
  421. */
  422. int snd_sbmixer_add_ctl(struct snd_sb *chip, const char *name, int index, int type, unsigned long value)
  423. {
  424. static struct snd_kcontrol_new newctls[] = {
  425. [SB_MIX_SINGLE] = {
  426. .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  427. .info = snd_sbmixer_info_single,
  428. .get = snd_sbmixer_get_single,
  429. .put = snd_sbmixer_put_single,
  430. },
  431. [SB_MIX_DOUBLE] = {
  432. .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  433. .info = snd_sbmixer_info_double,
  434. .get = snd_sbmixer_get_double,
  435. .put = snd_sbmixer_put_double,
  436. },
  437. [SB_MIX_INPUT_SW] = {
  438. .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  439. .info = snd_sb16mixer_info_input_sw,
  440. .get = snd_sb16mixer_get_input_sw,
  441. .put = snd_sb16mixer_put_input_sw,
  442. },
  443. [SB_MIX_CAPTURE_PRO] = {
  444. .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  445. .info = snd_sb8mixer_info_mux,
  446. .get = snd_sb8mixer_get_mux,
  447. .put = snd_sb8mixer_put_mux,
  448. },
  449. [SB_MIX_CAPTURE_DT019X] = {
  450. .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  451. .info = snd_dt019x_input_sw_info,
  452. .get = snd_dt019x_input_sw_get,
  453. .put = snd_dt019x_input_sw_put,
  454. },
  455. [SB_MIX_MONO_CAPTURE_ALS4K] = {
  456. .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  457. .info = snd_als4k_mono_capture_route_info,
  458. .get = snd_als4k_mono_capture_route_get,
  459. .put = snd_als4k_mono_capture_route_put,
  460. },
  461. };
  462. struct snd_kcontrol *ctl;
  463. int err;
  464. ctl = snd_ctl_new1(&newctls[type], chip);
  465. if (! ctl)
  466. return -ENOMEM;
  467. strlcpy(ctl->id.name, name, sizeof(ctl->id.name));
  468. ctl->id.index = index;
  469. ctl->private_value = value;
  470. if ((err = snd_ctl_add(chip->card, ctl)) < 0)
  471. return err;
  472. return 0;
  473. }
  474. /*
  475. * SB 2.0 specific mixer elements
  476. */
  477. static struct sbmix_elem snd_sb20_controls[] = {
  478. SB_SINGLE("Master Playback Volume", SB_DSP20_MASTER_DEV, 1, 7),
  479. SB_SINGLE("PCM Playback Volume", SB_DSP20_PCM_DEV, 1, 3),
  480. SB_SINGLE("Synth Playback Volume", SB_DSP20_FM_DEV, 1, 7),
  481. SB_SINGLE("CD Playback Volume", SB_DSP20_CD_DEV, 1, 7)
  482. };
  483. static unsigned char snd_sb20_init_values[][2] = {
  484. { SB_DSP20_MASTER_DEV, 0 },
  485. { SB_DSP20_FM_DEV, 0 },
  486. };
  487. /*
  488. * SB Pro specific mixer elements
  489. */
  490. static struct sbmix_elem snd_sbpro_controls[] = {
  491. SB_DOUBLE("Master Playback Volume",
  492. SB_DSP_MASTER_DEV, SB_DSP_MASTER_DEV, 5, 1, 7),
  493. SB_DOUBLE("PCM Playback Volume",
  494. SB_DSP_PCM_DEV, SB_DSP_PCM_DEV, 5, 1, 7),
  495. SB_SINGLE("PCM Playback Filter", SB_DSP_PLAYBACK_FILT, 5, 1),
  496. SB_DOUBLE("Synth Playback Volume",
  497. SB_DSP_FM_DEV, SB_DSP_FM_DEV, 5, 1, 7),
  498. SB_DOUBLE("CD Playback Volume", SB_DSP_CD_DEV, SB_DSP_CD_DEV, 5, 1, 7),
  499. SB_DOUBLE("Line Playback Volume",
  500. SB_DSP_LINE_DEV, SB_DSP_LINE_DEV, 5, 1, 7),
  501. SB_SINGLE("Mic Playback Volume", SB_DSP_MIC_DEV, 1, 3),
  502. {
  503. .name = "Capture Source",
  504. .type = SB_MIX_CAPTURE_PRO
  505. },
  506. SB_SINGLE("Capture Filter", SB_DSP_CAPTURE_FILT, 5, 1),
  507. SB_SINGLE("Capture Low-Pass Filter", SB_DSP_CAPTURE_FILT, 3, 1)
  508. };
  509. static unsigned char snd_sbpro_init_values[][2] = {
  510. { SB_DSP_MASTER_DEV, 0 },
  511. { SB_DSP_PCM_DEV, 0 },
  512. { SB_DSP_FM_DEV, 0 },
  513. };
  514. /*
  515. * SB16 specific mixer elements
  516. */
  517. static struct sbmix_elem snd_sb16_controls[] = {
  518. SB_DOUBLE("Master Playback Volume",
  519. SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31),
  520. SB_DOUBLE("PCM Playback Volume",
  521. SB_DSP4_PCM_DEV, (SB_DSP4_PCM_DEV + 1), 3, 3, 31),
  522. SB16_INPUT_SW("Synth Capture Route",
  523. SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 6, 5),
  524. SB_DOUBLE("Synth Playback Volume",
  525. SB_DSP4_SYNTH_DEV, (SB_DSP4_SYNTH_DEV + 1), 3, 3, 31),
  526. SB16_INPUT_SW("CD Capture Route",
  527. SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 2, 1),
  528. SB_DOUBLE("CD Playback Switch",
  529. SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1),
  530. SB_DOUBLE("CD Playback Volume",
  531. SB_DSP4_CD_DEV, (SB_DSP4_CD_DEV + 1), 3, 3, 31),
  532. SB16_INPUT_SW("Mic Capture Route",
  533. SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0),
  534. SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1),
  535. SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31),
  536. SB_SINGLE("Beep Volume", SB_DSP4_SPEAKER_DEV, 6, 3),
  537. SB_DOUBLE("Capture Volume",
  538. SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3),
  539. SB_DOUBLE("Playback Volume",
  540. SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3),
  541. SB16_INPUT_SW("Line Capture Route",
  542. SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 4, 3),
  543. SB_DOUBLE("Line Playback Switch",
  544. SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1),
  545. SB_DOUBLE("Line Playback Volume",
  546. SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31),
  547. SB_SINGLE("Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1),
  548. SB_SINGLE("3D Enhancement Switch", SB_DSP4_3DSE, 0, 1),
  549. SB_DOUBLE("Tone Control - Bass",
  550. SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15),
  551. SB_DOUBLE("Tone Control - Treble",
  552. SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15)
  553. };
  554. static unsigned char snd_sb16_init_values[][2] = {
  555. { SB_DSP4_MASTER_DEV + 0, 0 },
  556. { SB_DSP4_MASTER_DEV + 1, 0 },
  557. { SB_DSP4_PCM_DEV + 0, 0 },
  558. { SB_DSP4_PCM_DEV + 1, 0 },
  559. { SB_DSP4_SYNTH_DEV + 0, 0 },
  560. { SB_DSP4_SYNTH_DEV + 1, 0 },
  561. { SB_DSP4_INPUT_LEFT, 0 },
  562. { SB_DSP4_INPUT_RIGHT, 0 },
  563. { SB_DSP4_OUTPUT_SW, 0 },
  564. { SB_DSP4_SPEAKER_DEV, 0 },
  565. };
  566. /*
  567. * DT019x specific mixer elements
  568. */
  569. static struct sbmix_elem snd_dt019x_controls[] = {
  570. /* ALS4000 below has some parts which we might be lacking,
  571. * e.g. snd_als4000_ctl_mono_playback_switch - check it! */
  572. SB_DOUBLE("Master Playback Volume",
  573. SB_DT019X_MASTER_DEV, SB_DT019X_MASTER_DEV, 4, 0, 15),
  574. SB_DOUBLE("PCM Playback Switch",
  575. SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2, 1, 1),
  576. SB_DOUBLE("PCM Playback Volume",
  577. SB_DT019X_PCM_DEV, SB_DT019X_PCM_DEV, 4, 0, 15),
  578. SB_DOUBLE("Synth Playback Switch",
  579. SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4, 3, 1),
  580. SB_DOUBLE("Synth Playback Volume",
  581. SB_DT019X_SYNTH_DEV, SB_DT019X_SYNTH_DEV, 4, 0, 15),
  582. SB_DOUBLE("CD Playback Switch",
  583. SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1),
  584. SB_DOUBLE("CD Playback Volume",
  585. SB_DT019X_CD_DEV, SB_DT019X_CD_DEV, 4, 0, 15),
  586. SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1),
  587. SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7),
  588. SB_SINGLE("Beep Volume", SB_DT019X_SPKR_DEV, 0, 7),
  589. SB_DOUBLE("Line Playback Switch",
  590. SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1),
  591. SB_DOUBLE("Line Playback Volume",
  592. SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4, 0, 15),
  593. {
  594. .name = "Capture Source",
  595. .type = SB_MIX_CAPTURE_DT019X
  596. }
  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. static struct sbmix_elem snd_als4000_controls[] = {
  613. SB_DOUBLE("PCM Playback Switch",
  614. SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2, 1, 1),
  615. SB_DOUBLE("Synth Playback Switch",
  616. SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4, 3, 1),
  617. SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03),
  618. SB_SINGLE("Master Mono Playback Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1),
  619. {
  620. .name = "Master Mono Capture Route",
  621. .type = SB_MIX_MONO_CAPTURE_ALS4K
  622. },
  623. SB_SINGLE("Mono Playback Switch", SB_DT019X_OUTPUT_SW2, 0, 1),
  624. SB_SINGLE("Analog Loopback Switch", SB_ALS4000_MIC_IN_GAIN, 7, 0x01),
  625. SB_SINGLE("3D Control - Switch", SB_ALS4000_3D_SND_FX, 6, 0x01),
  626. SB_SINGLE("Digital Loopback Switch",
  627. SB_ALS4000_CR3_CONFIGURATION, 7, 0x01),
  628. /* FIXME: functionality of 3D controls might be swapped, I didn't find
  629. * a description of how to identify what is supposed to be what */
  630. SB_SINGLE("3D Control - Level", SB_ALS4000_3D_SND_FX, 0, 0x07),
  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. /* FIXME: ALS4000a.pdf mentions BBD (Bucket Brigade Device) time delay,
  634. * but what ALSA 3D attribute is that actually? "Center", "Depth",
  635. * "Wide" or "Space" or even "Level"? Assuming "Wide" for now... */
  636. SB_SINGLE("3D Control - Wide", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f),
  637. SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01),
  638. SB_SINGLE("Master Playback 8kHz / 20kHz LPF Switch",
  639. SB_ALS4000_FMDAC, 5, 0x01),
  640. #ifdef NOT_AVAILABLE
  641. SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01),
  642. SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND, 1, 0x1f),
  643. #endif
  644. };
  645. static unsigned char snd_als4000_init_values[][2] = {
  646. { SB_DSP4_MASTER_DEV + 0, 0 },
  647. { SB_DSP4_MASTER_DEV + 1, 0 },
  648. { SB_DSP4_PCM_DEV + 0, 0 },
  649. { SB_DSP4_PCM_DEV + 1, 0 },
  650. { SB_DSP4_SYNTH_DEV + 0, 0 },
  651. { SB_DSP4_SYNTH_DEV + 1, 0 },
  652. { SB_DSP4_SPEAKER_DEV, 0 },
  653. { SB_DSP4_OUTPUT_SW, 0 },
  654. { SB_DSP4_INPUT_LEFT, 0 },
  655. { SB_DSP4_INPUT_RIGHT, 0 },
  656. { SB_DT019X_OUTPUT_SW2, 0 },
  657. { SB_ALS4000_MIC_IN_GAIN, 0 },
  658. };
  659. /*
  660. */
  661. static int snd_sbmixer_init(struct snd_sb *chip,
  662. struct sbmix_elem *controls,
  663. int controls_count,
  664. unsigned char map[][2],
  665. int map_count,
  666. char *name)
  667. {
  668. unsigned long flags;
  669. struct snd_card *card = chip->card;
  670. int idx, err;
  671. /* mixer reset */
  672. spin_lock_irqsave(&chip->mixer_lock, flags);
  673. snd_sbmixer_write(chip, 0x00, 0x00);
  674. spin_unlock_irqrestore(&chip->mixer_lock, flags);
  675. /* mute and zero volume channels */
  676. for (idx = 0; idx < map_count; idx++) {
  677. spin_lock_irqsave(&chip->mixer_lock, flags);
  678. snd_sbmixer_write(chip, map[idx][0], map[idx][1]);
  679. spin_unlock_irqrestore(&chip->mixer_lock, flags);
  680. }
  681. for (idx = 0; idx < controls_count; idx++) {
  682. err = snd_sbmixer_add_ctl_elem(chip, &controls[idx]);
  683. if (err < 0)
  684. return err;
  685. }
  686. snd_component_add(card, name);
  687. strcpy(card->mixername, name);
  688. return 0;
  689. }
  690. int snd_sbmixer_new(struct snd_sb *chip)
  691. {
  692. struct snd_card *card;
  693. int err;
  694. if (snd_BUG_ON(!chip || !chip->card))
  695. return -EINVAL;
  696. card = chip->card;
  697. switch (chip->hardware) {
  698. case SB_HW_10:
  699. return 0; /* no mixer chip on SB1.x */
  700. case SB_HW_20:
  701. case SB_HW_201:
  702. if ((err = snd_sbmixer_init(chip,
  703. snd_sb20_controls,
  704. ARRAY_SIZE(snd_sb20_controls),
  705. snd_sb20_init_values,
  706. ARRAY_SIZE(snd_sb20_init_values),
  707. "CTL1335")) < 0)
  708. return err;
  709. break;
  710. case SB_HW_PRO:
  711. case SB_HW_JAZZ16:
  712. if ((err = snd_sbmixer_init(chip,
  713. snd_sbpro_controls,
  714. ARRAY_SIZE(snd_sbpro_controls),
  715. snd_sbpro_init_values,
  716. ARRAY_SIZE(snd_sbpro_init_values),
  717. "CTL1345")) < 0)
  718. return err;
  719. break;
  720. case SB_HW_16:
  721. case SB_HW_ALS100:
  722. case SB_HW_CS5530:
  723. if ((err = snd_sbmixer_init(chip,
  724. snd_sb16_controls,
  725. ARRAY_SIZE(snd_sb16_controls),
  726. snd_sb16_init_values,
  727. ARRAY_SIZE(snd_sb16_init_values),
  728. "CTL1745")) < 0)
  729. return err;
  730. break;
  731. case SB_HW_ALS4000:
  732. /* use only the first 16 controls from SB16 */
  733. err = snd_sbmixer_init(chip,
  734. snd_sb16_controls,
  735. 16,
  736. snd_sb16_init_values,
  737. ARRAY_SIZE(snd_sb16_init_values),
  738. "ALS4000");
  739. if (err < 0)
  740. return err;
  741. if ((err = snd_sbmixer_init(chip,
  742. snd_als4000_controls,
  743. ARRAY_SIZE(snd_als4000_controls),
  744. snd_als4000_init_values,
  745. ARRAY_SIZE(snd_als4000_init_values),
  746. "ALS4000")) < 0)
  747. return err;
  748. break;
  749. case SB_HW_DT019X:
  750. if ((err = snd_sbmixer_init(chip,
  751. snd_dt019x_controls,
  752. ARRAY_SIZE(snd_dt019x_controls),
  753. snd_dt019x_init_values,
  754. ARRAY_SIZE(snd_dt019x_init_values),
  755. "DT019X")) < 0)
  756. break;
  757. default:
  758. strcpy(card->mixername, "???");
  759. }
  760. return 0;
  761. }
  762. #ifdef CONFIG_PM
  763. static unsigned char sb20_saved_regs[] = {
  764. SB_DSP20_MASTER_DEV,
  765. SB_DSP20_PCM_DEV,
  766. SB_DSP20_FM_DEV,
  767. SB_DSP20_CD_DEV,
  768. };
  769. static unsigned char sbpro_saved_regs[] = {
  770. SB_DSP_MASTER_DEV,
  771. SB_DSP_PCM_DEV,
  772. SB_DSP_PLAYBACK_FILT,
  773. SB_DSP_FM_DEV,
  774. SB_DSP_CD_DEV,
  775. SB_DSP_LINE_DEV,
  776. SB_DSP_MIC_DEV,
  777. SB_DSP_CAPTURE_SOURCE,
  778. SB_DSP_CAPTURE_FILT,
  779. };
  780. static unsigned char sb16_saved_regs[] = {
  781. SB_DSP4_MASTER_DEV, SB_DSP4_MASTER_DEV + 1,
  782. SB_DSP4_3DSE,
  783. SB_DSP4_BASS_DEV, SB_DSP4_BASS_DEV + 1,
  784. SB_DSP4_TREBLE_DEV, SB_DSP4_TREBLE_DEV + 1,
  785. SB_DSP4_PCM_DEV, SB_DSP4_PCM_DEV + 1,
  786. SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT,
  787. SB_DSP4_SYNTH_DEV, SB_DSP4_SYNTH_DEV + 1,
  788. SB_DSP4_OUTPUT_SW,
  789. SB_DSP4_CD_DEV, SB_DSP4_CD_DEV + 1,
  790. SB_DSP4_LINE_DEV, SB_DSP4_LINE_DEV + 1,
  791. SB_DSP4_MIC_DEV,
  792. SB_DSP4_SPEAKER_DEV,
  793. SB_DSP4_IGAIN_DEV, SB_DSP4_IGAIN_DEV + 1,
  794. SB_DSP4_OGAIN_DEV, SB_DSP4_OGAIN_DEV + 1,
  795. SB_DSP4_MIC_AGC
  796. };
  797. static unsigned char dt019x_saved_regs[] = {
  798. SB_DT019X_MASTER_DEV,
  799. SB_DT019X_PCM_DEV,
  800. SB_DT019X_SYNTH_DEV,
  801. SB_DT019X_CD_DEV,
  802. SB_DT019X_MIC_DEV,
  803. SB_DT019X_SPKR_DEV,
  804. SB_DT019X_LINE_DEV,
  805. SB_DSP4_OUTPUT_SW,
  806. SB_DT019X_OUTPUT_SW2,
  807. SB_DT019X_CAPTURE_SW,
  808. };
  809. static unsigned char als4000_saved_regs[] = {
  810. /* please verify in dsheet whether regs to be added
  811. are actually real H/W or just dummy */
  812. SB_DSP4_MASTER_DEV, SB_DSP4_MASTER_DEV + 1,
  813. SB_DSP4_OUTPUT_SW,
  814. SB_DSP4_PCM_DEV, SB_DSP4_PCM_DEV + 1,
  815. SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT,
  816. SB_DSP4_SYNTH_DEV, SB_DSP4_SYNTH_DEV + 1,
  817. SB_DSP4_CD_DEV, SB_DSP4_CD_DEV + 1,
  818. SB_DSP4_MIC_DEV,
  819. SB_DSP4_SPEAKER_DEV,
  820. SB_DSP4_IGAIN_DEV, SB_DSP4_IGAIN_DEV + 1,
  821. SB_DSP4_OGAIN_DEV, SB_DSP4_OGAIN_DEV + 1,
  822. SB_DT019X_OUTPUT_SW2,
  823. SB_ALS4000_MONO_IO_CTRL,
  824. SB_ALS4000_MIC_IN_GAIN,
  825. SB_ALS4000_FMDAC,
  826. SB_ALS4000_3D_SND_FX,
  827. SB_ALS4000_3D_TIME_DELAY,
  828. SB_ALS4000_CR3_CONFIGURATION,
  829. };
  830. static void save_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs)
  831. {
  832. unsigned char *val = chip->saved_regs;
  833. if (snd_BUG_ON(num_regs > ARRAY_SIZE(chip->saved_regs)))
  834. return;
  835. for (; num_regs; num_regs--)
  836. *val++ = snd_sbmixer_read(chip, *regs++);
  837. }
  838. static void restore_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs)
  839. {
  840. unsigned char *val = chip->saved_regs;
  841. if (snd_BUG_ON(num_regs > ARRAY_SIZE(chip->saved_regs)))
  842. return;
  843. for (; num_regs; num_regs--)
  844. snd_sbmixer_write(chip, *regs++, *val++);
  845. }
  846. void snd_sbmixer_suspend(struct snd_sb *chip)
  847. {
  848. switch (chip->hardware) {
  849. case SB_HW_20:
  850. case SB_HW_201:
  851. save_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs));
  852. break;
  853. case SB_HW_PRO:
  854. case SB_HW_JAZZ16:
  855. save_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs));
  856. break;
  857. case SB_HW_16:
  858. case SB_HW_ALS100:
  859. case SB_HW_CS5530:
  860. save_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs));
  861. break;
  862. case SB_HW_ALS4000:
  863. save_mixer(chip, als4000_saved_regs, ARRAY_SIZE(als4000_saved_regs));
  864. break;
  865. case SB_HW_DT019X:
  866. save_mixer(chip, dt019x_saved_regs, ARRAY_SIZE(dt019x_saved_regs));
  867. break;
  868. default:
  869. break;
  870. }
  871. }
  872. void snd_sbmixer_resume(struct snd_sb *chip)
  873. {
  874. switch (chip->hardware) {
  875. case SB_HW_20:
  876. case SB_HW_201:
  877. restore_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs));
  878. break;
  879. case SB_HW_PRO:
  880. case SB_HW_JAZZ16:
  881. restore_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs));
  882. break;
  883. case SB_HW_16:
  884. case SB_HW_ALS100:
  885. case SB_HW_CS5530:
  886. restore_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs));
  887. break;
  888. case SB_HW_ALS4000:
  889. restore_mixer(chip, als4000_saved_regs, ARRAY_SIZE(als4000_saved_regs));
  890. break;
  891. case SB_HW_DT019X:
  892. restore_mixer(chip, dt019x_saved_regs, ARRAY_SIZE(dt019x_saved_regs));
  893. break;
  894. default:
  895. break;
  896. }
  897. }
  898. #endif