diff options
Diffstat (limited to 'sound/usb/6fire/pcm.c')
-rw-r--r-- | sound/usb/6fire/pcm.c | 97 |
1 files changed, 38 insertions, 59 deletions
diff --git a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c index ba62c7468ba8..b137b25865cc 100644 --- a/sound/usb/6fire/pcm.c +++ b/sound/usb/6fire/pcm.c | |||
@@ -17,26 +17,23 @@ | |||
17 | #include "pcm.h" | 17 | #include "pcm.h" |
18 | #include "chip.h" | 18 | #include "chip.h" |
19 | #include "comm.h" | 19 | #include "comm.h" |
20 | #include "control.h" | ||
20 | 21 | ||
21 | enum { | 22 | enum { |
22 | OUT_N_CHANNELS = 6, IN_N_CHANNELS = 4 | 23 | OUT_N_CHANNELS = 6, IN_N_CHANNELS = 4 |
23 | }; | 24 | }; |
24 | 25 | ||
25 | /* keep next two synced with | 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 | static const int rates_in_packet_size[] = { 228, 228, 420, 420, 404, 404 }; | 29 | static const int rates_in_packet_size[] = { 228, 228, 420, 420, 404, 404 }; |
28 | static const int rates_out_packet_size[] = { 228, 228, 420, 420, 604, 604 }; | 30 | static const int rates_out_packet_size[] = { 228, 228, 420, 420, 604, 604 }; |
29 | static const int rates[] = { 44100, 48000, 88200, 96000, 176400, 192000 }; | 31 | static const int rates[] = { 44100, 48000, 88200, 96000, 176400, 192000 }; |
30 | static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 }; | ||
31 | static const int rates_alsaid[] = { | 32 | static const int rates_alsaid[] = { |
32 | SNDRV_PCM_RATE_44100, SNDRV_PCM_RATE_48000, | 33 | SNDRV_PCM_RATE_44100, SNDRV_PCM_RATE_48000, |
33 | SNDRV_PCM_RATE_88200, SNDRV_PCM_RATE_96000, | 34 | SNDRV_PCM_RATE_88200, SNDRV_PCM_RATE_96000, |
34 | SNDRV_PCM_RATE_176400, SNDRV_PCM_RATE_192000 }; | 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 | enum { /* settings for pcm */ | 37 | enum { /* settings for pcm */ |
41 | OUT_EP = 6, IN_EP = 2, MAX_BUFSIZE = 128 * 1024 | 38 | OUT_EP = 6, IN_EP = 2, MAX_BUFSIZE = 128 * 1024 |
42 | }; | 39 | }; |
@@ -48,15 +45,6 @@ enum { /* pcm streaming states */ | |||
48 | STREAM_STOPPING | 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 | static const struct snd_pcm_hardware pcm_hw = { | 48 | static const struct snd_pcm_hardware pcm_hw = { |
61 | .info = SNDRV_PCM_INFO_MMAP | | 49 | .info = SNDRV_PCM_INFO_MMAP | |
62 | SNDRV_PCM_INFO_INTERLEAVED | | 50 | SNDRV_PCM_INFO_INTERLEAVED | |
@@ -64,7 +52,7 @@ static const struct snd_pcm_hardware pcm_hw = { | |||
64 | SNDRV_PCM_INFO_MMAP_VALID | | 52 | SNDRV_PCM_INFO_MMAP_VALID | |
65 | SNDRV_PCM_INFO_BATCH, | 53 | SNDRV_PCM_INFO_BATCH, |
66 | 54 | ||
67 | .formats = SNDRV_PCM_FMTBIT_S24_LE, | 55 | .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, |
68 | 56 | ||
69 | .rates = SNDRV_PCM_RATE_44100 | | 57 | .rates = SNDRV_PCM_RATE_44100 | |
70 | SNDRV_PCM_RATE_48000 | | 58 | SNDRV_PCM_RATE_48000 | |
@@ -87,57 +75,34 @@ static const struct snd_pcm_hardware pcm_hw = { | |||
87 | static int usb6fire_pcm_set_rate(struct pcm_runtime *rt) | 75 | static int usb6fire_pcm_set_rate(struct pcm_runtime *rt) |
88 | { | 76 | { |
89 | int ret; | 77 | int ret; |
90 | struct usb_device *device = rt->chip->dev; | 78 | struct control_runtime *ctrl_rt = rt->chip->control; |
91 | struct comm_runtime *comm_rt = rt->chip->comm; | ||
92 | 79 | ||
93 | if (rt->rate >= ARRAY_SIZE(rates)) | 80 | ctrl_rt->usb_streaming = false; |
94 | return -EINVAL; | 81 | ret = ctrl_rt->update_streaming(ctrl_rt); |
95 | /* disable streaming */ | ||
96 | ret = comm_rt->write16(comm_rt, 0x02, 0x00, 0x00, 0x00); | ||
97 | if (ret < 0) { | 82 | if (ret < 0) { |
98 | snd_printk(KERN_ERR PREFIX "error stopping streaming while " | 83 | snd_printk(KERN_ERR PREFIX "error stopping streaming while " |
99 | "setting samplerate %d.\n", rates[rt->rate]); | 84 | "setting samplerate %d.\n", rates[rt->rate]); |
100 | return ret; | 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 | 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) { | 89 | if (ret < 0) { |
115 | snd_printk(KERN_ERR PREFIX "error setting samplerate %d.\n", | 90 | snd_printk(KERN_ERR PREFIX "error setting samplerate %d.\n", |
116 | rates[rt->rate]); | 91 | rates[rt->rate]); |
117 | return ret; | 92 | return ret; |
118 | } | 93 | } |
119 | 94 | ||
120 | /* enable analog inputs and outputs | 95 | ret = ctrl_rt->set_channels(ctrl_rt, OUT_N_CHANNELS, IN_N_CHANNELS, |
121 | * (one bit per stereo-channel) */ | 96 | false, false); |
122 | ret = comm_rt->write16(comm_rt, 0x02, 0x02, | ||
123 | (1 << (OUT_N_CHANNELS / 2)) - 1, | ||
124 | (1 << (IN_N_CHANNELS / 2)) - 1); | ||
125 | if (ret < 0) { | 97 | if (ret < 0) { |
126 | snd_printk(KERN_ERR PREFIX "error initializing analog channels " | 98 | snd_printk(KERN_ERR PREFIX "error initializing channels " |
127 | "while setting samplerate %d.\n", | 99 | "while setting samplerate %d.\n", |
128 | rates[rt->rate]); | 100 | rates[rt->rate]); |
129 | return ret; | 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 | if (ret < 0) { | 106 | if (ret < 0) { |
142 | snd_printk(KERN_ERR PREFIX "error starting streaming while " | 107 | snd_printk(KERN_ERR PREFIX "error starting streaming while " |
143 | "setting samplerate %d.\n", rates[rt->rate]); | 108 | "setting samplerate %d.\n", rates[rt->rate]); |
@@ -168,12 +133,15 @@ static struct pcm_substream *usb6fire_pcm_get_substream( | |||
168 | static void usb6fire_pcm_stream_stop(struct pcm_runtime *rt) | 133 | static void usb6fire_pcm_stream_stop(struct pcm_runtime *rt) |
169 | { | 134 | { |
170 | int i; | 135 | int i; |
136 | struct control_runtime *ctrl_rt = rt->chip->control; | ||
171 | 137 | ||
172 | if (rt->stream_state != STREAM_DISABLED) { | 138 | if (rt->stream_state != STREAM_DISABLED) { |
173 | for (i = 0; i < PCM_N_URBS; i++) { | 139 | for (i = 0; i < PCM_N_URBS; i++) { |
174 | usb_kill_urb(&rt->in_urbs[i].instance); | 140 | usb_kill_urb(&rt->in_urbs[i].instance); |
175 | usb_kill_urb(&rt->out_urbs[i].instance); | 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 | rt->stream_state = STREAM_DISABLED; | 145 | rt->stream_state = STREAM_DISABLED; |
178 | } | 146 | } |
179 | } | 147 | } |
@@ -228,7 +196,7 @@ static void usb6fire_pcm_capture(struct pcm_substream *sub, struct pcm_urb *urb) | |||
228 | unsigned int total_length = 0; | 196 | unsigned int total_length = 0; |
229 | struct pcm_runtime *rt = snd_pcm_substream_chip(sub->instance); | 197 | struct pcm_runtime *rt = snd_pcm_substream_chip(sub->instance); |
230 | struct snd_pcm_runtime *alsa_rt = sub->instance->runtime; | 198 | struct snd_pcm_runtime *alsa_rt = sub->instance->runtime; |
231 | u32 *src = (u32 *) urb->buffer; | 199 | u32 *src = NULL; |
232 | u32 *dest = (u32 *) (alsa_rt->dma_area + sub->dma_off | 200 | u32 *dest = (u32 *) (alsa_rt->dma_area + sub->dma_off |
233 | * (alsa_rt->frame_bits >> 3)); | 201 | * (alsa_rt->frame_bits >> 3)); |
234 | u32 *dest_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size | 202 | u32 *dest_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size |
@@ -244,7 +212,12 @@ static void usb6fire_pcm_capture(struct pcm_substream *sub, struct pcm_urb *urb) | |||
244 | else | 212 | else |
245 | frame_count = 0; | 213 | frame_count = 0; |
246 | 214 | ||
247 | src = (u32 *) (urb->buffer + total_length); | 215 | if (alsa_rt->format == SNDRV_PCM_FORMAT_S24_LE) |
216 | src = (u32 *) (urb->buffer + total_length); | ||
217 | else if (alsa_rt->format == SNDRV_PCM_FORMAT_S32_LE) | ||
218 | src = (u32 *) (urb->buffer - 1 + total_length); | ||
219 | else | ||
220 | return; | ||
248 | src++; /* skip leading 4 bytes of every packet */ | 221 | src++; /* skip leading 4 bytes of every packet */ |
249 | total_length += urb->packets[i].length; | 222 | total_length += urb->packets[i].length; |
250 | for (frame = 0; frame < frame_count; frame++) { | 223 | for (frame = 0; frame < frame_count; frame++) { |
@@ -274,9 +247,18 @@ static void usb6fire_pcm_playback(struct pcm_substream *sub, | |||
274 | * (alsa_rt->frame_bits >> 3)); | 247 | * (alsa_rt->frame_bits >> 3)); |
275 | u32 *src_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size | 248 | u32 *src_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size |
276 | * (alsa_rt->frame_bits >> 3)); | 249 | * (alsa_rt->frame_bits >> 3)); |
277 | u32 *dest = (u32 *) urb->buffer; | 250 | u32 *dest; |
278 | int bytes_per_frame = alsa_rt->channels << 2; | 251 | int bytes_per_frame = alsa_rt->channels << 2; |
279 | 252 | ||
253 | if (alsa_rt->format == SNDRV_PCM_FORMAT_S32_LE) | ||
254 | dest = (u32 *) (urb->buffer - 1); | ||
255 | else if (alsa_rt->format == SNDRV_PCM_FORMAT_S24_LE) | ||
256 | dest = (u32 *) (urb->buffer); | ||
257 | else { | ||
258 | snd_printk(KERN_ERR PREFIX "Unknown sample format."); | ||
259 | return; | ||
260 | } | ||
261 | |||
280 | for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) { | 262 | for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) { |
281 | /* at least 4 header bytes for valid packet. | 263 | /* at least 4 header bytes for valid packet. |
282 | * after that: 32 bits per sample for analog channels */ | 264 | * after that: 32 bits per sample for analog channels */ |
@@ -456,7 +438,7 @@ static int usb6fire_pcm_close(struct snd_pcm_substream *alsa_sub) | |||
456 | /* all substreams closed? if so, stop streaming */ | 438 | /* all substreams closed? if so, stop streaming */ |
457 | if (!rt->playback.instance && !rt->capture.instance) { | 439 | if (!rt->playback.instance && !rt->capture.instance) { |
458 | usb6fire_pcm_stream_stop(rt); | 440 | usb6fire_pcm_stream_stop(rt); |
459 | rt->rate = -1; | 441 | rt->rate = ARRAY_SIZE(rates); |
460 | } | 442 | } |
461 | } | 443 | } |
462 | mutex_unlock(&rt->stream_mutex); | 444 | mutex_unlock(&rt->stream_mutex); |
@@ -480,7 +462,6 @@ static int usb6fire_pcm_prepare(struct snd_pcm_substream *alsa_sub) | |||
480 | struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); | 462 | struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); |
481 | struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub); | 463 | struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub); |
482 | struct snd_pcm_runtime *alsa_rt = alsa_sub->runtime; | 464 | struct snd_pcm_runtime *alsa_rt = alsa_sub->runtime; |
483 | int i; | ||
484 | int ret; | 465 | int ret; |
485 | 466 | ||
486 | if (rt->panic) | 467 | if (rt->panic) |
@@ -493,12 +474,10 @@ static int usb6fire_pcm_prepare(struct snd_pcm_substream *alsa_sub) | |||
493 | sub->period_off = 0; | 474 | sub->period_off = 0; |
494 | 475 | ||
495 | if (rt->stream_state == STREAM_DISABLED) { | 476 | if (rt->stream_state == STREAM_DISABLED) { |
496 | for (i = 0; i < ARRAY_SIZE(rates); i++) | 477 | for (rt->rate = 0; rt->rate < ARRAY_SIZE(rates); rt->rate++) |
497 | if (alsa_rt->rate == rates[i]) { | 478 | if (alsa_rt->rate == rates[rt->rate]) |
498 | rt->rate = i; | ||
499 | break; | 479 | break; |
500 | } | 480 | if (rt->rate == ARRAY_SIZE(rates)) { |
501 | if (i == ARRAY_SIZE(rates)) { | ||
502 | mutex_unlock(&rt->stream_mutex); | 481 | mutex_unlock(&rt->stream_mutex); |
503 | snd_printk("invalid rate %d in prepare.\n", | 482 | snd_printk("invalid rate %d in prepare.\n", |
504 | alsa_rt->rate); | 483 | alsa_rt->rate); |
@@ -613,7 +592,7 @@ int __devinit usb6fire_pcm_init(struct sfire_chip *chip) | |||
613 | 592 | ||
614 | rt->chip = chip; | 593 | rt->chip = chip; |
615 | rt->stream_state = STREAM_DISABLED; | 594 | rt->stream_state = STREAM_DISABLED; |
616 | rt->rate = -1; | 595 | rt->rate = ARRAY_SIZE(rates); |
617 | init_waitqueue_head(&rt->stream_wait_queue); | 596 | init_waitqueue_head(&rt->stream_wait_queue); |
618 | mutex_init(&rt->stream_mutex); | 597 | mutex_init(&rt->stream_mutex); |
619 | 598 | ||