diff options
author | Palash Bandyopadhyay <palash.bandyopadhyay@conexant.com> | 2010-07-06 17:12:25 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-10-20 23:17:10 -0400 |
commit | 64fbf44455260684fa5bfdd3121af3d0ef0b48dd (patch) | |
tree | 3e823c84d187b8de0731cd0b703b341abd92350e /drivers/media/video/cx231xx/cx231xx-audio.c | |
parent | 47b75ec14653f12f9fd6fd76bfd5891ba35e1e79 (diff) |
[media] cx231xx: Added support for Carraera, Shelby, RDx_253S and VIDEO_GRABBER
Added support for new cx231xx boards - Carraera, Shelby, RDx_253S and
VIDEO_GRABBER.
[mchehab@redhat.com: Fix a merge conflict with BKL removal patches]
Signed-off-by: Palash Bandyopadhyay <palash.bandyopadhyay@conexant.com>
Signed-off-by: Devin Heitmueller <dheitmueller@hauppauge.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/cx231xx/cx231xx-audio.c')
-rw-r--r-- | drivers/media/video/cx231xx/cx231xx-audio.c | 189 |
1 files changed, 179 insertions, 10 deletions
diff --git a/drivers/media/video/cx231xx/cx231xx-audio.c b/drivers/media/video/cx231xx/cx231xx-audio.c index 7cae95a2245e..6ac418cc6895 100644 --- a/drivers/media/video/cx231xx/cx231xx-audio.c +++ b/drivers/media/video/cx231xx/cx231xx-audio.c | |||
@@ -75,6 +75,30 @@ static int cx231xx_isoc_audio_deinit(struct cx231xx *dev) | |||
75 | return 0; | 75 | return 0; |
76 | } | 76 | } |
77 | 77 | ||
78 | static int cx231xx_bulk_audio_deinit(struct cx231xx *dev) | ||
79 | { | ||
80 | int i; | ||
81 | |||
82 | dprintk("Stopping bulk\n"); | ||
83 | |||
84 | for (i = 0; i < CX231XX_AUDIO_BUFS; i++) { | ||
85 | if (dev->adev.urb[i]) { | ||
86 | if (!irqs_disabled()) | ||
87 | usb_kill_urb(dev->adev.urb[i]); | ||
88 | else | ||
89 | usb_unlink_urb(dev->adev.urb[i]); | ||
90 | |||
91 | usb_free_urb(dev->adev.urb[i]); | ||
92 | dev->adev.urb[i] = NULL; | ||
93 | |||
94 | kfree(dev->adev.transfer_buffer[i]); | ||
95 | dev->adev.transfer_buffer[i] = NULL; | ||
96 | } | ||
97 | } | ||
98 | |||
99 | return 0; | ||
100 | } | ||
101 | |||
78 | static void cx231xx_audio_isocirq(struct urb *urb) | 102 | static void cx231xx_audio_isocirq(struct urb *urb) |
79 | { | 103 | { |
80 | struct cx231xx *dev = urb->context; | 104 | struct cx231xx *dev = urb->context; |
@@ -158,14 +182,92 @@ static void cx231xx_audio_isocirq(struct urb *urb) | |||
158 | return; | 182 | return; |
159 | } | 183 | } |
160 | 184 | ||
185 | static void cx231xx_audio_bulkirq(struct urb *urb) | ||
186 | { | ||
187 | struct cx231xx *dev = urb->context; | ||
188 | unsigned int oldptr; | ||
189 | int period_elapsed = 0; | ||
190 | int status; | ||
191 | unsigned char *cp; | ||
192 | unsigned int stride; | ||
193 | struct snd_pcm_substream *substream; | ||
194 | struct snd_pcm_runtime *runtime; | ||
195 | |||
196 | switch (urb->status) { | ||
197 | case 0: /* success */ | ||
198 | case -ETIMEDOUT: /* NAK */ | ||
199 | break; | ||
200 | case -ECONNRESET: /* kill */ | ||
201 | case -ENOENT: | ||
202 | case -ESHUTDOWN: | ||
203 | return; | ||
204 | default: /* error */ | ||
205 | dprintk("urb completition error %d.\n", urb->status); | ||
206 | break; | ||
207 | } | ||
208 | |||
209 | if (dev->adev.capture_pcm_substream) { | ||
210 | substream = dev->adev.capture_pcm_substream; | ||
211 | runtime = substream->runtime; | ||
212 | stride = runtime->frame_bits >> 3; | ||
213 | |||
214 | if (1) { | ||
215 | int length = urb->actual_length / | ||
216 | stride; | ||
217 | cp = (unsigned char *)urb->transfer_buffer; | ||
218 | |||
219 | oldptr = dev->adev.hwptr_done_capture; | ||
220 | if (oldptr + length >= runtime->buffer_size) { | ||
221 | unsigned int cnt; | ||
222 | |||
223 | cnt = runtime->buffer_size - oldptr; | ||
224 | memcpy(runtime->dma_area + oldptr * stride, cp, | ||
225 | cnt * stride); | ||
226 | memcpy(runtime->dma_area, cp + cnt * stride, | ||
227 | length * stride - cnt * stride); | ||
228 | } else { | ||
229 | memcpy(runtime->dma_area + oldptr * stride, cp, | ||
230 | length * stride); | ||
231 | } | ||
232 | |||
233 | snd_pcm_stream_lock(substream); | ||
234 | |||
235 | dev->adev.hwptr_done_capture += length; | ||
236 | if (dev->adev.hwptr_done_capture >= | ||
237 | runtime->buffer_size) | ||
238 | dev->adev.hwptr_done_capture -= | ||
239 | runtime->buffer_size; | ||
240 | |||
241 | dev->adev.capture_transfer_done += length; | ||
242 | if (dev->adev.capture_transfer_done >= | ||
243 | runtime->period_size) { | ||
244 | dev->adev.capture_transfer_done -= | ||
245 | runtime->period_size; | ||
246 | period_elapsed = 1; | ||
247 | } | ||
248 | snd_pcm_stream_unlock(substream); | ||
249 | } | ||
250 | if (period_elapsed) | ||
251 | snd_pcm_period_elapsed(substream); | ||
252 | } | ||
253 | urb->status = 0; | ||
254 | |||
255 | status = usb_submit_urb(urb, GFP_ATOMIC); | ||
256 | if (status < 0) { | ||
257 | cx231xx_errdev("resubmit of audio urb failed (error=%i)\n", | ||
258 | status); | ||
259 | } | ||
260 | return; | ||
261 | } | ||
262 | |||
161 | static int cx231xx_init_audio_isoc(struct cx231xx *dev) | 263 | static int cx231xx_init_audio_isoc(struct cx231xx *dev) |
162 | { | 264 | { |
163 | int i, errCode; | 265 | int i, errCode; |
164 | int sb_size; | 266 | int sb_size; |
165 | 267 | ||
166 | cx231xx_info("%s: Starting AUDIO transfers\n", __func__); | 268 | cx231xx_info("%s: Starting ISO AUDIO transfers\n", __func__); |
167 | 269 | ||
168 | sb_size = CX231XX_NUM_AUDIO_PACKETS * dev->adev.max_pkt_size; | 270 | sb_size = CX231XX_ISO_NUM_AUDIO_PACKETS * dev->adev.max_pkt_size; |
169 | 271 | ||
170 | for (i = 0; i < CX231XX_AUDIO_BUFS; i++) { | 272 | for (i = 0; i < CX231XX_AUDIO_BUFS; i++) { |
171 | struct urb *urb; | 273 | struct urb *urb; |
@@ -176,7 +278,7 @@ static int cx231xx_init_audio_isoc(struct cx231xx *dev) | |||
176 | return -ENOMEM; | 278 | return -ENOMEM; |
177 | 279 | ||
178 | memset(dev->adev.transfer_buffer[i], 0x80, sb_size); | 280 | memset(dev->adev.transfer_buffer[i], 0x80, sb_size); |
179 | urb = usb_alloc_urb(CX231XX_NUM_AUDIO_PACKETS, GFP_ATOMIC); | 281 | urb = usb_alloc_urb(CX231XX_ISO_NUM_AUDIO_PACKETS, GFP_ATOMIC); |
180 | if (!urb) { | 282 | if (!urb) { |
181 | cx231xx_errdev("usb_alloc_urb failed!\n"); | 283 | cx231xx_errdev("usb_alloc_urb failed!\n"); |
182 | for (j = 0; j < i; j++) { | 284 | for (j = 0; j < i; j++) { |
@@ -194,10 +296,10 @@ static int cx231xx_init_audio_isoc(struct cx231xx *dev) | |||
194 | urb->transfer_buffer = dev->adev.transfer_buffer[i]; | 296 | urb->transfer_buffer = dev->adev.transfer_buffer[i]; |
195 | urb->interval = 1; | 297 | urb->interval = 1; |
196 | urb->complete = cx231xx_audio_isocirq; | 298 | urb->complete = cx231xx_audio_isocirq; |
197 | urb->number_of_packets = CX231XX_NUM_AUDIO_PACKETS; | 299 | urb->number_of_packets = CX231XX_ISO_NUM_AUDIO_PACKETS; |
198 | urb->transfer_buffer_length = sb_size; | 300 | urb->transfer_buffer_length = sb_size; |
199 | 301 | ||
200 | for (j = k = 0; j < CX231XX_NUM_AUDIO_PACKETS; | 302 | for (j = k = 0; j < CX231XX_ISO_NUM_AUDIO_PACKETS; |
201 | j++, k += dev->adev.max_pkt_size) { | 303 | j++, k += dev->adev.max_pkt_size) { |
202 | urb->iso_frame_desc[j].offset = k; | 304 | urb->iso_frame_desc[j].offset = k; |
203 | urb->iso_frame_desc[j].length = dev->adev.max_pkt_size; | 305 | urb->iso_frame_desc[j].length = dev->adev.max_pkt_size; |
@@ -216,6 +318,59 @@ static int cx231xx_init_audio_isoc(struct cx231xx *dev) | |||
216 | return errCode; | 318 | return errCode; |
217 | } | 319 | } |
218 | 320 | ||
321 | static int cx231xx_init_audio_bulk(struct cx231xx *dev) | ||
322 | { | ||
323 | int i, errCode; | ||
324 | int sb_size; | ||
325 | |||
326 | cx231xx_info("%s: Starting BULK AUDIO transfers\n", __func__); | ||
327 | |||
328 | sb_size = CX231XX_NUM_AUDIO_PACKETS * dev->adev.max_pkt_size; | ||
329 | |||
330 | for (i = 0; i < CX231XX_AUDIO_BUFS; i++) { | ||
331 | struct urb *urb; | ||
332 | int j; | ||
333 | |||
334 | dev->adev.transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC); | ||
335 | if (!dev->adev.transfer_buffer[i]) | ||
336 | return -ENOMEM; | ||
337 | |||
338 | memset(dev->adev.transfer_buffer[i], 0x80, sb_size); | ||
339 | urb = usb_alloc_urb(CX231XX_NUM_AUDIO_PACKETS, GFP_ATOMIC); | ||
340 | if (!urb) { | ||
341 | cx231xx_errdev("usb_alloc_urb failed!\n"); | ||
342 | for (j = 0; j < i; j++) { | ||
343 | usb_free_urb(dev->adev.urb[j]); | ||
344 | kfree(dev->adev.transfer_buffer[j]); | ||
345 | } | ||
346 | return -ENOMEM; | ||
347 | } | ||
348 | |||
349 | urb->dev = dev->udev; | ||
350 | urb->context = dev; | ||
351 | urb->pipe = usb_rcvbulkpipe(dev->udev, | ||
352 | dev->adev.end_point_addr); | ||
353 | urb->transfer_flags = 0; | ||
354 | urb->transfer_buffer = dev->adev.transfer_buffer[i]; | ||
355 | urb->complete = cx231xx_audio_bulkirq; | ||
356 | urb->transfer_buffer_length = sb_size; | ||
357 | |||
358 | dev->adev.urb[i] = urb; | ||
359 | |||
360 | } | ||
361 | |||
362 | for (i = 0; i < CX231XX_AUDIO_BUFS; i++) { | ||
363 | errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC); | ||
364 | if (errCode < 0) { | ||
365 | cx231xx_bulk_audio_deinit(dev); | ||
366 | return errCode; | ||
367 | } | ||
368 | } | ||
369 | |||
370 | return errCode; | ||
371 | } | ||
372 | |||
373 | |||
219 | static int cx231xx_cmd(struct cx231xx *dev, int cmd, int arg) | 374 | static int cx231xx_cmd(struct cx231xx *dev, int cmd, int arg) |
220 | { | 375 | { |
221 | dprintk("%s transfer\n", (dev->adev.capture_stream == STREAM_ON) ? | 376 | dprintk("%s transfer\n", (dev->adev.capture_stream == STREAM_ON) ? |
@@ -225,7 +380,12 @@ static int cx231xx_cmd(struct cx231xx *dev, int cmd, int arg) | |||
225 | case CX231XX_CAPTURE_STREAM_EN: | 380 | case CX231XX_CAPTURE_STREAM_EN: |
226 | if (dev->adev.capture_stream == STREAM_OFF && arg == 1) { | 381 | if (dev->adev.capture_stream == STREAM_OFF && arg == 1) { |
227 | dev->adev.capture_stream = STREAM_ON; | 382 | dev->adev.capture_stream = STREAM_ON; |
228 | cx231xx_init_audio_isoc(dev); | 383 | if (is_fw_load(dev) == 0) |
384 | cx25840_call(dev, core, load_fw); | ||
385 | if (dev->USE_ISO) | ||
386 | cx231xx_init_audio_isoc(dev); | ||
387 | else | ||
388 | cx231xx_init_audio_bulk(dev); | ||
229 | } else if (dev->adev.capture_stream == STREAM_ON && arg == 0) { | 389 | } else if (dev->adev.capture_stream == STREAM_ON && arg == 0) { |
230 | dev->adev.capture_stream = STREAM_OFF; | 390 | dev->adev.capture_stream = STREAM_OFF; |
231 | cx231xx_isoc_audio_deinit(dev); | 391 | cx231xx_isoc_audio_deinit(dev); |
@@ -300,7 +460,10 @@ static int snd_cx231xx_capture_open(struct snd_pcm_substream *substream) | |||
300 | 460 | ||
301 | /* set alternate setting for audio interface */ | 461 | /* set alternate setting for audio interface */ |
302 | /* 1 - 48000 samples per sec */ | 462 | /* 1 - 48000 samples per sec */ |
303 | ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 1); | 463 | if (dev->USE_ISO) |
464 | ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 1); | ||
465 | else | ||
466 | ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 0); | ||
304 | if (ret < 0) { | 467 | if (ret < 0) { |
305 | cx231xx_errdev("failed to set alternate setting !\n"); | 468 | cx231xx_errdev("failed to set alternate setting !\n"); |
306 | 469 | ||
@@ -330,6 +493,9 @@ static int snd_cx231xx_pcm_close(struct snd_pcm_substream *substream) | |||
330 | 493 | ||
331 | dprintk("closing device\n"); | 494 | dprintk("closing device\n"); |
332 | 495 | ||
496 | /* inform hardware to start streaming */ | ||
497 | ret = cx231xx_capture_start(dev, 0, Audio); | ||
498 | |||
333 | /* set alternate setting for audio interface */ | 499 | /* set alternate setting for audio interface */ |
334 | /* 1 - 48000 samples per sec */ | 500 | /* 1 - 48000 samples per sec */ |
335 | ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 0); | 501 | ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 0); |
@@ -339,9 +505,6 @@ static int snd_cx231xx_pcm_close(struct snd_pcm_substream *substream) | |||
339 | return ret; | 505 | return ret; |
340 | } | 506 | } |
341 | 507 | ||
342 | /* inform hardware to start streaming */ | ||
343 | ret = cx231xx_capture_start(dev, 0, Audio); | ||
344 | |||
345 | dev->mute = 1; | 508 | dev->mute = 1; |
346 | mutex_lock(&dev->lock); | 509 | mutex_lock(&dev->lock); |
347 | dev->adev.users--; | 510 | dev->adev.users--; |
@@ -391,6 +554,11 @@ static int snd_cx231xx_hw_capture_free(struct snd_pcm_substream *substream) | |||
391 | 554 | ||
392 | static int snd_cx231xx_prepare(struct snd_pcm_substream *substream) | 555 | static int snd_cx231xx_prepare(struct snd_pcm_substream *substream) |
393 | { | 556 | { |
557 | struct cx231xx *dev = snd_pcm_substream_chip(substream); | ||
558 | |||
559 | dev->adev.hwptr_done_capture = 0; | ||
560 | dev->adev.capture_transfer_done = 0; | ||
561 | |||
394 | return 0; | 562 | return 0; |
395 | } | 563 | } |
396 | 564 | ||
@@ -495,6 +663,7 @@ static int cx231xx_audio_init(struct cx231xx *dev) | |||
495 | pcm->info_flags = 0; | 663 | pcm->info_flags = 0; |
496 | pcm->private_data = dev; | 664 | pcm->private_data = dev; |
497 | strcpy(pcm->name, "Conexant cx231xx Capture"); | 665 | strcpy(pcm->name, "Conexant cx231xx Capture"); |
666 | snd_card_set_dev(card, &dev->udev->dev); | ||
498 | strcpy(card->driver, "Cx231xx-Audio"); | 667 | strcpy(card->driver, "Cx231xx-Audio"); |
499 | strcpy(card->shortname, "Cx231xx Audio"); | 668 | strcpy(card->shortname, "Cx231xx Audio"); |
500 | strcpy(card->longname, "Conexant cx231xx Audio"); | 669 | strcpy(card->longname, "Conexant cx231xx Audio"); |