diff options
-rw-r--r-- | linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c | 212 | ||||
-rw-r--r-- | linux/drivers/media/dvb/ttusb-dec/ttusb_dec.h | 6 |
2 files changed, 151 insertions, 67 deletions
diff --git a/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c index 0457657f4..18f892542 100644 --- a/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c +++ b/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c @@ -42,6 +42,13 @@ ttusb_dec_send_command(ttusb_dec_t * dec, const u8 command, const u8 params[], dprintk("%s\n", __FUNCTION__); + if ((result = down_interruptible(&dec->usb_sem))) { + + printk("%s: Failed to down usb semaphore.\n", __FUNCTION__); + return result; + + } + b[0] = 0xaa; b[1] = ++dec->trans_count; b[2] = command; @@ -63,16 +70,27 @@ ttusb_dec_send_command(ttusb_dec_t * dec, const u8 command, const u8 params[], usb_bulk_msg(dec->udev, dec->command_pipe, b, sizeof (b), &actual_len, HZ); - if (result < 0) + if (result < 0) { + + printk("%s: command bulk message failed: error %d\n", + __FUNCTION__, result); + up(&dec->usb_sem); return result; + } + result = usb_bulk_msg(dec->udev, dec->result_pipe, c, sizeof (c), &actual_len, HZ); - if (result < 0) + if (result < 0) { + + printk("%s: result bulk message failed: error %d\n", + __FUNCTION__, result); + up(&dec->usb_sem); return result; - else { + + } else { if (debug) { @@ -86,12 +104,25 @@ ttusb_dec_send_command(ttusb_dec_t * dec, const u8 command, const u8 params[], if (cmd_result && c[3] > 0) memcpy(cmd_result, &c[4], c[3]); + up(&dec->usb_sem); return c[3]; } } +static int +ttusb_dec_av_pes2ts_cb(void *priv, unsigned char *data) +{ + + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) priv; + + dvbdmxfeed->cb.ts(data, 188, 0, 0, &dvbdmxfeed->feed.ts, DMX_OK); + + return 0; + +} + static void ttusb_dec_set_pids(ttusb_dec_t * dec) { @@ -112,6 +143,17 @@ ttusb_dec_set_pids(ttusb_dec_t * dec) ttusb_dec_send_command(dec, 0x50, b, sizeof (b), NULL); + if (!down_interruptible(&dec->pes2ts_sem)) { + + dvb_filter_pes2ts_init(&dec->a_pes2ts, dec->pid[DMX_PES_AUDIO], + ttusb_dec_av_pes2ts_cb, dec->demux.feed); + dvb_filter_pes2ts_init(&dec->v_pes2ts, dec->pid[DMX_PES_VIDEO], + ttusb_dec_av_pes2ts_cb, dec->demux.feed); + + up(&dec->pes2ts_sem); + + } + } static int @@ -192,8 +234,15 @@ ttusb_dec_process_av_pes(ttusb_dec_t * dec, u8 * av_pes, int length) memcpy(&dec->v_pes[dec->v_pes_length], &av_pes[12], prebytes); - dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes, - dec->v_pes_length + prebytes); + if (!down_interruptible(&dec->pes2ts_sem)) { + + dvb_filter_pes2ts(&dec->v_pes2ts, + dec->v_pes, + dec->v_pes_length + + prebytes); + + up(&dec->pes2ts_sem); + } } @@ -243,9 +292,19 @@ ttusb_dec_process_av_pes(ttusb_dec_t * dec, u8 * av_pes, int length) htons(dec->v_pes_length - 6 + postbytes); memcpy(&dec->v_pes[4], &v_pes_payload_length, 2); - if (postbytes == 0) - dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes, - dec->v_pes_length); + if (postbytes == 0) { + + if (!down_interruptible(&dec->pes2ts_sem)) { + + dvb_filter_pes2ts(&dec->v_pes2ts, + dec->v_pes, + dec->v_pes_length); + + up(&dec->pes2ts_sem); + + } + + } break; @@ -256,7 +315,7 @@ ttusb_dec_process_av_pes(ttusb_dec_t * dec, u8 * av_pes, int length) break; default: - printk("%s: unknown AV_PES type (%02x).\n", __FUNCTION__, + printk("%s: unknown AV_PES type: %02x.\n", __FUNCTION__, av_pes[2]); break; @@ -376,9 +435,6 @@ ttusb_dec_process_urb(struct urb *urb) ttusb_dec_t *dec = urb->context; - if (!dec->iso_streaming) - return; - if (!urb->status) { int i; @@ -399,7 +455,10 @@ ttusb_dec_process_urb(struct urb *urb) } else { - dprintk("%s: urb error: %d\n", __FUNCTION__, urb->status); + /* -ENOENT is expected when unlinking urbs */ + if (urb->status != -ENOENT) + dprintk("%s: urb error: %d\n", __FUNCTION__, + urb->status); } @@ -449,74 +508,87 @@ ttusb_dec_stop_iso_xfer(ttusb_dec_t * dec) dprintk("%s\n", __FUNCTION__); - if (dec->iso_streaming) - for (i = 0; i < ISO_BUF_COUNT; i++) - usb_unlink_urb(dec->iso_urb[i]); + if (down_interruptible(&dec->iso_sem)) + return; - dec->iso_streaming = 0; + dec->iso_stream_count--; -} + if (!dec->iso_stream_count) { -static int -ttusb_dec_av_pes2ts_cb(void *priv, unsigned char *data) -{ + u8 b0[] = { 0x00 }; - struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) priv; + for (i = 0; i < ISO_BUF_COUNT; i++) + usb_unlink_urb(dec->iso_urb[i]); - dvbdmxfeed->cb.ts(data, 188, 0, 0, &dvbdmxfeed->feed.ts, DMX_OK); + ttusb_dec_send_command(dec, 0x81, b0, sizeof (b0), NULL); - return 0; + } + + up(&dec->iso_sem); } static int -ttusb_dec_start_iso_xfer(ttusb_dec_t * dec) +ttusb_dec_start_iso_xfer(ttusb_dec_t *dec) { int i, result; - u8 b0[] = { 0x05 }; dprintk("%s\n", __FUNCTION__); - ttusb_dec_send_command(dec, 0x80, b0, sizeof (b0), NULL); + if (down_interruptible(&dec->iso_sem)) + return -EAGAIN; - if (dec->iso_streaming) { + if (!dec->iso_stream_count) { - printk("%s: iso xfer already running!\n", __FUNCTION__); - return 0; + u8 b0[] = { 0x05 }; - } + ttusb_dec_send_command(dec, 0x80, b0, sizeof (b0), NULL); - ttusb_dec_setup_urbs(dec); + ttusb_dec_setup_urbs(dec); - for (i = 0; i < ISO_BUF_COUNT; i++) { + for (i = 0; i < ISO_BUF_COUNT; i++) { - if ((result = usb_submit_urb(dec->iso_urb[i]))) { + if ((result = usb_submit_urb(dec->iso_urb[i]))) { - ttusb_dec_stop_iso_xfer(dec); - printk("%s: failed urb submission (%i: errno = %i)!\n", - __FUNCTION__, i, result); - return result; + printk("%s: failed urb submission %d: error %d\n", + __FUNCTION__, i, result); + + while (i) { + + usb_unlink_urb(dec->iso_urb[i]); + i--; + + } + + up(&dec->iso_sem); + return result; + + } } + dec->av_pes_state = 0; + dec->v_pes_postbytes = 0; + } + dec->iso_stream_count++; + + up(&dec->iso_sem); + if (!dec->interface) { - usb_set_interface(dec->udev, 0, 8); /* Can't do this at mod init time - weird */ + /* Can't do this at mod init time - weird. + * Don't stick this at the top of this function either - + * it will cause the send_command to time out trying to get + * a result + */ + usb_set_interface(dec->udev, 0, 8); dec->interface = 8; } - dec->iso_streaming = 1; - dec->av_pes_state = 0; - dec->v_pes_postbytes = 0; - - dvb_filter_pes2ts_init(&dec->a_pes2ts, dec->pid[DMX_PES_AUDIO], - ttusb_dec_av_pes2ts_cb, dec->demux.feed); - dvb_filter_pes2ts_init(&dec->v_pes2ts, dec->pid[DMX_PES_VIDEO], - ttusb_dec_av_pes2ts_cb, dec->demux.feed); return 0; @@ -534,9 +606,6 @@ ttusb_dec_start_feed(struct dvb_demux_feed *dvbdmxfeed) if (!dvbdmx->dmx.frontend) return -EINVAL; - if (dec->iso_streaming) - ttusb_dec_stop_iso_xfer(dec); - dprintk(" pid: 0x%04X\n", dvbdmxfeed->pid); switch (dvbdmxfeed->type) { @@ -615,14 +684,11 @@ ttusb_dec_stop_feed(struct dvb_demux_feed *dvbdmxfeed) { ttusb_dec_t *dec = dvbdmxfeed->demux->priv; - u8 b0[] = { 0x00 }; dprintk("%s\n", __FUNCTION__); ttusb_dec_stop_iso_xfer(dec); - ttusb_dec_send_command(dec, 0x81, b0, sizeof (b0), NULL); - return 0; } @@ -710,8 +776,9 @@ ttusb_dec_init_usb(ttusb_dec_t * dec) dprintk("%s\n", __FUNCTION__); - usb_set_configuration(dec->udev, 1); - usb_set_interface(dec->udev, 0, 0); + sema_init(&dec->usb_sem, 1); + sema_init(&dec->iso_sem, 1); + spin_lock_init(&dec->iso_stream_count_lock); dec->command_pipe = usb_sndbulkpipe(dec->udev, COMMAND_PIPE); dec->result_pipe = usb_rcvbulkpipe(dec->udev, RESULT_PIPE); @@ -794,8 +861,6 @@ ttusb_dec_init_stb(ttusb_dec_t * dec) dprintk("%s\n", __FUNCTION__); - usb_set_configuration(dec->udev, 1); - result = ttusb_dec_send_command(dec, 0x08, NULL, 0, c); if (result == 0x10) @@ -813,7 +878,7 @@ ttusb_dec_init_dvb(ttusb_dec_t * dec) if ((result = dvb_register_adapter(&dec->adapter, "dec2000")) < 0) { - printk("%s: dvb_register_adapter failed (errno = %d)\n", + printk("%s: dvb_register_adapter failed: error %d\n", __FUNCTION__, result); return result; @@ -847,7 +912,7 @@ ttusb_dec_init_dvb(ttusb_dec_t * dec) if ((result = dvb_dmx_init(&dec->demux)) < 0) { - printk("%s: dvb_dmx_init failed (errno = %d)\n", __FUNCTION__, + printk("%s: dvb_dmx_init failed: error %d\n", __FUNCTION__, result); dvb_unregister_i2c_bus(ttusb_dec_i2c_master_xfer, dec->adapter, @@ -864,7 +929,7 @@ ttusb_dec_init_dvb(ttusb_dec_t * dec) if ((result = dvb_dmxdev_init(&dec->dmxdev, dec->adapter)) < 0) { - printk("%s: dvb_dmxdev_init failed (errno = %d)\n", + printk("%s: dvb_dmxdev_init failed: error %d\n", __FUNCTION__, result); dvb_dmx_release(&dec->demux); @@ -885,7 +950,7 @@ ttusb_dec_init_dvb(ttusb_dec_t * dec) dec->demux.dmx.add_frontend(&dec->demux.dmx, &dec->frontend)) < 0) { - printk("%s: dvb_dmx_init failed (errno = %d)\n", __FUNCTION__, + printk("%s: dvb_dmx_init failed: error %d\n", __FUNCTION__, result); dvb_dmxdev_release(&dec->dmxdev); @@ -902,7 +967,7 @@ ttusb_dec_init_dvb(ttusb_dec_t * dec) dec->demux.dmx.connect_frontend(&dec->demux.dmx, &dec->frontend)) < 0) { - printk("%s: dvb_dmx_init failed (errno = %d)\n", __FUNCTION__, + printk("%s: dvb_dmx_init failed: error %d\n", __FUNCTION__, result); dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend); @@ -916,6 +981,8 @@ ttusb_dec_init_dvb(ttusb_dec_t * dec) } + sema_init(&dec->pes2ts_sem, 1); + return 0; } @@ -935,6 +1002,21 @@ ttusb_dec_exit_dvb(ttusb_dec_t * dec) } +static void +ttusb_dec_exit_usb(ttusb_dec_t * dec) +{ + + int i; + + dprintk("%s\n", __FUNCTION__); + + for (i = 0; i < ISO_BUF_COUNT; i++) + usb_unlink_urb(dec->iso_urb[i]); + + ttusb_dec_free_iso_urbs(dec); + +} + static void * ttusb_dec_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id) @@ -978,12 +1060,10 @@ ttusb_dec_disconnect(struct usb_device *udev, void *data) ttusb_dec_t *dec = data; - ttusb_dec_stop_iso_xfer(dec); + ttusb_dec_exit_usb(dec); ttusb_dec_exit_dvb(dec); - ttusb_dec_free_iso_urbs(dec); - kfree(dec); } @@ -1014,7 +1094,7 @@ ttusb_dec_init(void) if ((result = usb_register(&ttusb_dec_driver)) < 0) { - printk("%s: initialisation failed (Error %d).\n", __FUNCTION__, + printk("%s: initialisation failed: error %d.\n", __FUNCTION__, result); return result; diff --git a/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.h b/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.h index d66edadc6..b658e7ad0 100644 --- a/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.h +++ b/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.h @@ -22,6 +22,7 @@ #ifndef _TTUSB_DEC_H #define _TTUSB_DEC_H +#include "asm/semaphore.h" #include "dmxdev.h" #include "dvb_demux.h" #include "dvb_filter.h" @@ -60,11 +61,13 @@ typedef struct ttusb_dec_s { unsigned int result_pipe; unsigned int stream_pipe; int interface; + struct semaphore usb_sem; void *iso_buffer; dma_addr_t iso_dma_handle; struct urb *iso_urb[ISO_BUF_COUNT]; - int iso_streaming; + int iso_stream_count; + struct semaphore iso_sem; u8 av_pes[MAX_AV_PES_LENGTH + 4]; int av_pes_state; @@ -73,6 +76,7 @@ typedef struct ttusb_dec_s { dvb_filter_pes2ts_t a_pes2ts; dvb_filter_pes2ts_t v_pes2ts; + struct semaphore pes2ts_sem; u8 v_pes[16 + MAX_AV_PES_LENGTH]; int v_pes_length; |