Commit 2475b0d407614ea5a41b8325d45c614d94087088

Authored by Torsten Schenk
Committed by Takashi Iwai
1 parent b84610b95f

ALSA: 6fire - Add support of digital-thru mixer

Digital Thru mixer element added (device can act as converter optical<->coax)

Signed-off-by: Torsten Schenk <torsten.schenk@zoho.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>

Showing 3 changed files with 137 additions and 47 deletions Side-by-side Diff

sound/usb/6fire/control.c
... ... @@ -65,6 +65,15 @@
65 65 { 0 } /* TERMINATING ENTRY */
66 66 };
67 67  
  68 +static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 };
  69 +/* values to write to soundcard register for all samplerates */
  70 +static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01};
  71 +static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00};
  72 +
  73 +enum {
  74 + DIGITAL_THRU_ONLY_SAMPLERATE = 3
  75 +};
  76 +
68 77 static void usb6fire_control_master_vol_update(struct control_runtime *rt)
69 78 {
70 79 struct comm_runtime *comm_rt = rt->chip->comm;
... ... @@ -95,6 +104,67 @@
95 104 }
96 105 }
97 106  
  107 +static int usb6fire_control_set_rate(struct control_runtime *rt, int rate)
  108 +{
  109 + int ret;
  110 + struct usb_device *device = rt->chip->dev;
  111 + struct comm_runtime *comm_rt = rt->chip->comm;
  112 +
  113 + if (rate < 0 || rate >= CONTROL_N_RATES)
  114 + return -EINVAL;
  115 +
  116 + ret = usb_set_interface(device, 1, rates_altsetting[rate]);
  117 + if (ret < 0)
  118 + return ret;
  119 +
  120 + /* set soundcard clock */
  121 + ret = comm_rt->write16(comm_rt, 0x02, 0x01, rates_6fire_vl[rate],
  122 + rates_6fire_vh[rate]);
  123 + if (ret < 0)
  124 + return ret;
  125 +
  126 + return 0;
  127 +}
  128 +
  129 +static int usb6fire_control_set_channels(
  130 + struct control_runtime *rt, int n_analog_out,
  131 + int n_analog_in, bool spdif_out, bool spdif_in)
  132 +{
  133 + int ret;
  134 + struct comm_runtime *comm_rt = rt->chip->comm;
  135 +
  136 + /* enable analog inputs and outputs
  137 + * (one bit per stereo-channel) */
  138 + ret = comm_rt->write16(comm_rt, 0x02, 0x02,
  139 + (1 << (n_analog_out / 2)) - 1,
  140 + (1 << (n_analog_in / 2)) - 1);
  141 + if (ret < 0)
  142 + return ret;
  143 +
  144 + /* disable digital inputs and outputs */
  145 + /* TODO: use spdif_x to enable/disable digital channels */
  146 + ret = comm_rt->write16(comm_rt, 0x02, 0x03, 0x00, 0x00);
  147 + if (ret < 0)
  148 + return ret;
  149 +
  150 + return 0;
  151 +}
  152 +
  153 +static int usb6fire_control_streaming_update(struct control_runtime *rt)
  154 +{
  155 + struct comm_runtime *comm_rt = rt->chip->comm;
  156 +
  157 + if (comm_rt) {
  158 + if (!rt->usb_streaming && rt->digital_thru_switch)
  159 + usb6fire_control_set_rate(rt,
  160 + DIGITAL_THRU_ONLY_SAMPLERATE);
  161 + return comm_rt->write16(comm_rt, 0x02, 0x00, 0x00,
  162 + (rt->usb_streaming ? 0x01 : 0x00) |
  163 + (rt->digital_thru_switch ? 0x08 : 0x00));
  164 + }
  165 + return -EINVAL;
  166 +}
  167 +
98 168 static int usb6fire_control_master_vol_info(struct snd_kcontrol *kcontrol,
99 169 struct snd_ctl_elem_info *uinfo)
100 170 {
... ... @@ -195,6 +265,28 @@
195 265 return 0;
196 266 }
197 267  
  268 +static int usb6fire_control_digital_thru_put(struct snd_kcontrol *kcontrol,
  269 + struct snd_ctl_elem_value *ucontrol)
  270 +{
  271 + struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
  272 + int changed = 0;
  273 +
  274 + if (rt->digital_thru_switch != ucontrol->value.integer.value[0]) {
  275 + rt->digital_thru_switch = ucontrol->value.integer.value[0];
  276 + usb6fire_control_streaming_update(rt);
  277 + changed = 1;
  278 + }
  279 + return changed;
  280 +}
  281 +
  282 +static int usb6fire_control_digital_thru_get(struct snd_kcontrol *kcontrol,
  283 + struct snd_ctl_elem_value *ucontrol)
  284 +{
  285 + struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
  286 + ucontrol->value.integer.value[0] = rt->digital_thru_switch;
  287 + return 0;
  288 +}
  289 +
198 290 static struct __devinitdata snd_kcontrol_new elements[] = {
199 291 {
200 292 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
... ... @@ -223,6 +315,15 @@
223 315 .get = usb6fire_control_opt_coax_get,
224 316 .put = usb6fire_control_opt_coax_put
225 317 },
  318 + {
  319 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  320 + .name = "Digital Thru Playback Route",
  321 + .index = 0,
  322 + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
  323 + .info = snd_ctl_boolean_mono_info,
  324 + .get = usb6fire_control_digital_thru_get,
  325 + .put = usb6fire_control_digital_thru_put
  326 + },
226 327 {}
227 328 };
228 329  
... ... @@ -238,6 +339,9 @@
238 339 return -ENOMEM;
239 340  
240 341 rt->chip = chip;
  342 + rt->update_streaming = usb6fire_control_streaming_update;
  343 + rt->set_rate = usb6fire_control_set_rate;
  344 + rt->set_channels = usb6fire_control_set_channels;
241 345  
242 346 i = 0;
243 347 while (init_data[i].type) {
... ... @@ -249,6 +353,7 @@
249 353 usb6fire_control_opt_coax_update(rt);
250 354 usb6fire_control_line_phono_update(rt);
251 355 usb6fire_control_master_vol_update(rt);
  356 + usb6fire_control_streaming_update(rt);
252 357  
253 358 i = 0;
254 359 while (elements[i].name) {
sound/usb/6fire/control.h
... ... @@ -21,12 +21,29 @@
21 21 CONTROL_MAX_ELEMENTS = 32
22 22 };
23 23  
  24 +enum {
  25 + CONTROL_RATE_44KHZ,
  26 + CONTROL_RATE_48KHZ,
  27 + CONTROL_RATE_88KHZ,
  28 + CONTROL_RATE_96KHZ,
  29 + CONTROL_RATE_176KHZ,
  30 + CONTROL_RATE_192KHZ,
  31 + CONTROL_N_RATES
  32 +};
  33 +
24 34 struct control_runtime {
  35 + int (*update_streaming)(struct control_runtime *rt);
  36 + int (*set_rate)(struct control_runtime *rt, int rate);
  37 + int (*set_channels)(struct control_runtime *rt, int n_analog_out,
  38 + int n_analog_in, bool spdif_out, bool spdif_in);
  39 +
25 40 struct sfire_chip *chip;
26 41  
27 42 struct snd_kcontrol *element[CONTROL_MAX_ELEMENTS];
28 43 bool opt_coax_switch;
29 44 bool line_phono_switch;
  45 + bool digital_thru_switch;
  46 + bool usb_streaming;
30 47 u8 master_vol;
31 48 };
32 49  
sound/usb/6fire/pcm.c
... ... @@ -17,26 +17,23 @@
17 17 #include "pcm.h"
18 18 #include "chip.h"
19 19 #include "comm.h"
  20 +#include "control.h"
20 21  
21 22 enum {
22 23 OUT_N_CHANNELS = 6, IN_N_CHANNELS = 4
23 24 };
24 25  
25 26 /* keep next two synced with
26   - * FW_EP_W_MAX_PACKET_SIZE[] and RATES_MAX_PACKET_SIZE */
  27 + * FW_EP_W_MAX_PACKET_SIZE[] and RATES_MAX_PACKET_SIZE
  28 + * and CONTROL_RATE_XXX in control.h */
27 29 static const int rates_in_packet_size[] = { 228, 228, 420, 420, 404, 404 };
28 30 static const int rates_out_packet_size[] = { 228, 228, 420, 420, 604, 604 };
29 31 static const int rates[] = { 44100, 48000, 88200, 96000, 176400, 192000 };
30   -static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 };
31 32 static const int rates_alsaid[] = {
32 33 SNDRV_PCM_RATE_44100, SNDRV_PCM_RATE_48000,
33 34 SNDRV_PCM_RATE_88200, SNDRV_PCM_RATE_96000,
34 35 SNDRV_PCM_RATE_176400, SNDRV_PCM_RATE_192000 };
35 36  
36   -/* values to write to soundcard register for all samplerates */
37   -static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01};
38   -static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00};
39   -
40 37 enum { /* settings for pcm */
41 38 OUT_EP = 6, IN_EP = 2, MAX_BUFSIZE = 128 * 1024
42 39 };
... ... @@ -48,15 +45,6 @@
48 45 STREAM_STOPPING
49 46 };
50 47  
51   -enum { /* pcm sample rates (also index into RATES_XXX[]) */
52   - RATE_44KHZ,
53   - RATE_48KHZ,
54   - RATE_88KHZ,
55   - RATE_96KHZ,
56   - RATE_176KHZ,
57   - RATE_192KHZ
58   -};
59   -
60 48 static const struct snd_pcm_hardware pcm_hw = {
61 49 .info = SNDRV_PCM_INFO_MMAP |
62 50 SNDRV_PCM_INFO_INTERLEAVED |
63 51  
64 52  
65 53  
66 54  
67 55  
68 56  
69 57  
... ... @@ -87,57 +75,34 @@
87 75 static int usb6fire_pcm_set_rate(struct pcm_runtime *rt)
88 76 {
89 77 int ret;
90   - struct usb_device *device = rt->chip->dev;
91   - struct comm_runtime *comm_rt = rt->chip->comm;
  78 + struct control_runtime *ctrl_rt = rt->chip->control;
92 79  
93   - if (rt->rate >= ARRAY_SIZE(rates))
94   - return -EINVAL;
95   - /* disable streaming */
96   - ret = comm_rt->write16(comm_rt, 0x02, 0x00, 0x00, 0x00);
  80 + ctrl_rt->usb_streaming = false;
  81 + ret = ctrl_rt->update_streaming(ctrl_rt);
97 82 if (ret < 0) {
98 83 snd_printk(KERN_ERR PREFIX "error stopping streaming while "
99 84 "setting samplerate %d.\n", rates[rt->rate]);
100 85 return ret;
101 86 }
102 87  
103   - ret = usb_set_interface(device, 1, rates_altsetting[rt->rate]);
  88 + ret = ctrl_rt->set_rate(ctrl_rt, rt->rate);
104 89 if (ret < 0) {
105   - snd_printk(KERN_ERR PREFIX "error setting interface "
106   - "altsetting %d for samplerate %d.\n",
107   - rates_altsetting[rt->rate], rates[rt->rate]);
108   - return ret;
109   - }
110   -
111   - /* set soundcard clock */
112   - ret = comm_rt->write16(comm_rt, 0x02, 0x01, rates_6fire_vl[rt->rate],
113   - rates_6fire_vh[rt->rate]);
114   - if (ret < 0) {
115 90 snd_printk(KERN_ERR PREFIX "error setting samplerate %d.\n",
116 91 rates[rt->rate]);
117 92 return ret;
118 93 }
119 94  
120   - /* enable analog inputs and outputs
121   - * (one bit per stereo-channel) */
122   - ret = comm_rt->write16(comm_rt, 0x02, 0x02,
123   - (1 << (OUT_N_CHANNELS / 2)) - 1,
124   - (1 << (IN_N_CHANNELS / 2)) - 1);
  95 + ret = ctrl_rt->set_channels(ctrl_rt, OUT_N_CHANNELS, IN_N_CHANNELS,
  96 + false, false);
125 97 if (ret < 0) {
126   - snd_printk(KERN_ERR PREFIX "error initializing analog channels "
  98 + snd_printk(KERN_ERR PREFIX "error initializing channels "
127 99 "while setting samplerate %d.\n",
128 100 rates[rt->rate]);
129 101 return ret;
130 102 }
131   - /* disable digital inputs and outputs */
132   - ret = comm_rt->write16(comm_rt, 0x02, 0x03, 0x00, 0x00);
133   - if (ret < 0) {
134   - snd_printk(KERN_ERR PREFIX "error initializing digital "
135   - "channels while setting samplerate %d.\n",
136   - rates[rt->rate]);
137   - return ret;
138   - }
139 103  
140   - ret = comm_rt->write16(comm_rt, 0x02, 0x00, 0x00, 0x01);
  104 + ctrl_rt->usb_streaming = true;
  105 + ret = ctrl_rt->update_streaming(ctrl_rt);
141 106 if (ret < 0) {
142 107 snd_printk(KERN_ERR PREFIX "error starting streaming while "
143 108 "setting samplerate %d.\n", rates[rt->rate]);
144 109  
... ... @@ -168,12 +133,15 @@
168 133 static void usb6fire_pcm_stream_stop(struct pcm_runtime *rt)
169 134 {
170 135 int i;
  136 + struct control_runtime *ctrl_rt = rt->chip->control;
171 137  
172 138 if (rt->stream_state != STREAM_DISABLED) {
173 139 for (i = 0; i < PCM_N_URBS; i++) {
174 140 usb_kill_urb(&rt->in_urbs[i].instance);
175 141 usb_kill_urb(&rt->out_urbs[i].instance);
176 142 }
  143 + ctrl_rt->usb_streaming = false;
  144 + ctrl_rt->update_streaming(ctrl_rt);
177 145 rt->stream_state = STREAM_DISABLED;
178 146 }
179 147 }