gus_mixer.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Copyright (c) by Jaroslav Kysela <[email protected]>
  4. * Routines for control of ICS 2101 chip and "mixer" in GF1 chip
  5. */
  6. #include <linux/time.h>
  7. #include <linux/wait.h>
  8. #include <sound/core.h>
  9. #include <sound/control.h>
  10. #include <sound/gus.h>
  11. /*
  12. *
  13. */
  14. #define GF1_SINGLE(xname, xindex, shift, invert) \
  15. { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
  16. .info = snd_gf1_info_single, \
  17. .get = snd_gf1_get_single, .put = snd_gf1_put_single, \
  18. .private_value = shift | (invert << 8) }
  19. #define snd_gf1_info_single snd_ctl_boolean_mono_info
  20. static int snd_gf1_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
  21. {
  22. struct snd_gus_card *gus = snd_kcontrol_chip(kcontrol);
  23. int shift = kcontrol->private_value & 0xff;
  24. int invert = (kcontrol->private_value >> 8) & 1;
  25. ucontrol->value.integer.value[0] = (gus->mix_cntrl_reg >> shift) & 1;
  26. if (invert)
  27. ucontrol->value.integer.value[0] ^= 1;
  28. return 0;
  29. }
  30. static int snd_gf1_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
  31. {
  32. struct snd_gus_card *gus = snd_kcontrol_chip(kcontrol);
  33. unsigned long flags;
  34. int shift = kcontrol->private_value & 0xff;
  35. int invert = (kcontrol->private_value >> 8) & 1;
  36. int change;
  37. unsigned char oval, nval;
  38. nval = ucontrol->value.integer.value[0] & 1;
  39. if (invert)
  40. nval ^= 1;
  41. nval <<= shift;
  42. spin_lock_irqsave(&gus->reg_lock, flags);
  43. oval = gus->mix_cntrl_reg;
  44. nval = (oval & ~(1 << shift)) | nval;
  45. change = nval != oval;
  46. outb(gus->mix_cntrl_reg = nval, GUSP(gus, MIXCNTRLREG));
  47. outb(gus->gf1.active_voice = 0, GUSP(gus, GF1PAGE));
  48. spin_unlock_irqrestore(&gus->reg_lock, flags);
  49. return change;
  50. }
  51. #define ICS_DOUBLE(xname, xindex, addr) \
  52. { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
  53. .info = snd_ics_info_double, \
  54. .get = snd_ics_get_double, .put = snd_ics_put_double, \
  55. .private_value = addr }
  56. static int snd_ics_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
  57. {
  58. uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
  59. uinfo->count = 2;
  60. uinfo->value.integer.min = 0;
  61. uinfo->value.integer.max = 127;
  62. return 0;
  63. }
  64. static int snd_ics_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
  65. {
  66. struct snd_gus_card *gus = snd_kcontrol_chip(kcontrol);
  67. unsigned long flags;
  68. int addr = kcontrol->private_value & 0xff;
  69. unsigned char left, right;
  70. spin_lock_irqsave(&gus->reg_lock, flags);
  71. left = gus->gf1.ics_regs[addr][0];
  72. right = gus->gf1.ics_regs[addr][1];
  73. spin_unlock_irqrestore(&gus->reg_lock, flags);
  74. ucontrol->value.integer.value[0] = left & 127;
  75. ucontrol->value.integer.value[1] = right & 127;
  76. return 0;
  77. }
  78. static int snd_ics_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
  79. {
  80. struct snd_gus_card *gus = snd_kcontrol_chip(kcontrol);
  81. unsigned long flags;
  82. int addr = kcontrol->private_value & 0xff;
  83. int change;
  84. unsigned char val1, val2, oval1, oval2;
  85. val1 = ucontrol->value.integer.value[0] & 127;
  86. val2 = ucontrol->value.integer.value[1] & 127;
  87. spin_lock_irqsave(&gus->reg_lock, flags);
  88. oval1 = gus->gf1.ics_regs[addr][0];
  89. oval2 = gus->gf1.ics_regs[addr][1];
  90. change = val1 != oval1 || val2 != oval2;
  91. gus->gf1.ics_regs[addr][0] = val1;
  92. gus->gf1.ics_regs[addr][1] = val2;
  93. if (gus->ics_flag && gus->ics_flipped &&
  94. (addr == SNDRV_ICS_GF1_DEV || addr == SNDRV_ICS_MASTER_DEV))
  95. swap(val1, val2);
  96. addr <<= 3;
  97. outb(addr | 0, GUSP(gus, MIXCNTRLPORT));
  98. outb(1, GUSP(gus, MIXDATAPORT));
  99. outb(addr | 2, GUSP(gus, MIXCNTRLPORT));
  100. outb((unsigned char) val1, GUSP(gus, MIXDATAPORT));
  101. outb(addr | 1, GUSP(gus, MIXCNTRLPORT));
  102. outb(2, GUSP(gus, MIXDATAPORT));
  103. outb(addr | 3, GUSP(gus, MIXCNTRLPORT));
  104. outb((unsigned char) val2, GUSP(gus, MIXDATAPORT));
  105. spin_unlock_irqrestore(&gus->reg_lock, flags);
  106. return change;
  107. }
  108. static const struct snd_kcontrol_new snd_gf1_controls[] = {
  109. GF1_SINGLE("Master Playback Switch", 0, 1, 1),
  110. GF1_SINGLE("Line Switch", 0, 0, 1),
  111. GF1_SINGLE("Mic Switch", 0, 2, 0)
  112. };
  113. static const struct snd_kcontrol_new snd_ics_controls[] = {
  114. GF1_SINGLE("Master Playback Switch", 0, 1, 1),
  115. ICS_DOUBLE("Master Playback Volume", 0, SNDRV_ICS_MASTER_DEV),
  116. ICS_DOUBLE("Synth Playback Volume", 0, SNDRV_ICS_GF1_DEV),
  117. GF1_SINGLE("Line Switch", 0, 0, 1),
  118. ICS_DOUBLE("Line Playback Volume", 0, SNDRV_ICS_LINE_DEV),
  119. GF1_SINGLE("Mic Switch", 0, 2, 0),
  120. ICS_DOUBLE("Mic Playback Volume", 0, SNDRV_ICS_MIC_DEV),
  121. ICS_DOUBLE("CD Playback Volume", 0, SNDRV_ICS_CD_DEV)
  122. };
  123. int snd_gf1_new_mixer(struct snd_gus_card * gus)
  124. {
  125. struct snd_card *card;
  126. unsigned int idx, max;
  127. int err;
  128. if (snd_BUG_ON(!gus))
  129. return -EINVAL;
  130. card = gus->card;
  131. if (snd_BUG_ON(!card))
  132. return -EINVAL;
  133. if (gus->ics_flag)
  134. snd_component_add(card, "ICS2101");
  135. if (card->mixername[0] == '\0') {
  136. strcpy(card->mixername, gus->ics_flag ? "GF1,ICS2101" : "GF1");
  137. } else {
  138. if (gus->ics_flag)
  139. strcat(card->mixername, ",ICS2101");
  140. strcat(card->mixername, ",GF1");
  141. }
  142. if (!gus->ics_flag) {
  143. max = gus->ess_flag ? 1 : ARRAY_SIZE(snd_gf1_controls);
  144. for (idx = 0; idx < max; idx++) {
  145. err = snd_ctl_add(card, snd_ctl_new1(&snd_gf1_controls[idx], gus));
  146. if (err < 0)
  147. return err;
  148. }
  149. } else {
  150. for (idx = 0; idx < ARRAY_SIZE(snd_ics_controls); idx++) {
  151. err = snd_ctl_add(card, snd_ctl_new1(&snd_ics_controls[idx], gus));
  152. if (err < 0)
  153. return err;
  154. }
  155. }
  156. return 0;
  157. }