diff options
Diffstat (limited to 'linux/drivers')
-rw-r--r-- | linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c | 152 |
1 files changed, 114 insertions, 38 deletions
diff --git a/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c index b2df5535f..a75509993 100644 --- a/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c +++ b/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c @@ -41,6 +41,7 @@ #include "dvb_net.h" static int debug = 0; +static int output_avpes = 0; #define dprintk if (debug) printk @@ -48,14 +49,15 @@ static int debug = 0; #define COMMAND_PIPE 0x03 #define RESULT_PIPE 0x84 -#define STREAM_PIPE 0x88 +#define IN_PIPE 0x88 +#define OUT_PIPE 0x07 #define COMMAND_PACKET_SIZE 0x3c #define ARM_PACKET_SIZE 0x1000 #define ISO_BUF_COUNT 0x04 #define FRAMES_PER_ISO_BUF 0x04 -#define ISO_FRAME_SIZE 0x0380 +#define ISO_FRAME_SIZE 0x03FF #define MAX_AV_PES_LENGTH 6144 @@ -69,14 +71,22 @@ enum ttusb_dec_model { }; enum ttusb_dec_packet_type { - PACKET_AV_PES, - PACKET_SECTION + TTUSB_DEC_PACKET_AV_PES, + TTUSB_DEC_PACKET_SECTION, + TTUSB_DEC_PACKET_EMPTY +}; + +enum ttusb_dec_interface { + TTUSB_DEC_INTERFACE_INITIAL, + TTUSB_DEC_INTERFACE_IN, + TTUSB_DEC_INTERFACE_OUT }; struct ttusb_dec { enum ttusb_dec_model model; char *model_name; char *firmware_name; + int can_playback; /* DVB bits */ struct dvb_adapter *adapter; @@ -92,13 +102,14 @@ struct ttusb_dec { int hi_band; /* USB bits */ - struct usb_device *udev; - u8 trans_count; - unsigned int command_pipe; - unsigned int result_pipe; - unsigned int stream_pipe; - int interface; - struct semaphore usb_sem; + struct usb_device *udev; + u8 trans_count; + unsigned int command_pipe; + unsigned int result_pipe; + unsigned int in_pipe; + unsigned int out_pipe; + enum ttusb_dec_interface interface; + struct semaphore usb_sem; void *iso_buffer; dma_addr_t iso_dma_handle; @@ -111,6 +122,7 @@ struct ttusb_dec { int packet_state; int packet_length; int packet_payload_length; + u16 next_packet_id; int av_pes_stream_count; int filter_stream_count; @@ -336,6 +348,13 @@ static void ttusb_dec_process_av_pes(struct ttusb_dec *dec, u8 *av_pes, return; } + if (output_avpes) { + dec->av_filter->feed->cb.ts(av_pes, length, 0, 0, + &dec->av_filter->feed->feed.ts, + DMX_OK); + return; + } + switch (av_pes[2]) { case 0x01: { /* VideoStream */ @@ -439,6 +458,7 @@ static void ttusb_dec_process_packet(struct ttusb_dec *dec) { int i; u16 csum = 0; + u16 packet_id; if (dec->packet_length % 2) { printk("%s: odd sized packet - discarding\n", __FUNCTION__); @@ -453,18 +473,34 @@ static void ttusb_dec_process_packet(struct ttusb_dec *dec) return; } + packet_id = dec->packet[dec->packet_length - 4] << 8; + packet_id += dec->packet[dec->packet_length - 3]; + + if ((packet_id != dec->next_packet_id) && dec->next_packet_id) { + printk("%s: warning: lost packets between %u and %u\n", + __FUNCTION__, dec->next_packet_id - 1, packet_id); + } + + if (packet_id == 0xffff) + dec->next_packet_id = 0x8000; + else + dec->next_packet_id = packet_id + 1; + switch (dec->packet_type) { - case PACKET_AV_PES: + case TTUSB_DEC_PACKET_AV_PES: if (dec->av_pes_stream_count) ttusb_dec_process_av_pes(dec, dec->packet, dec->packet_payload_length); break; - case PACKET_SECTION: + case TTUSB_DEC_PACKET_SECTION: if (dec->filter_stream_count) ttusb_dec_process_filter(dec, dec->packet, dec->packet_payload_length); break; + + case TTUSB_DEC_PACKET_EMPTY: + break; } } @@ -513,15 +549,25 @@ static void ttusb_dec_process_urb_frame(struct ttusb_dec *dec, u8 *b, case 4: dec->packet[dec->packet_length++] = *b++; - if (dec->packet_length == 3) { + if (dec->packet_length == 2) { if (dec->packet[0] == 'A' && dec->packet[1] == 'V') { - dec->packet_type = PACKET_AV_PES; + dec->packet_type = + TTUSB_DEC_PACKET_AV_PES; dec->packet_state++; } else if (dec->packet[0] == 'S') { - dec->packet_type = PACKET_SECTION; + dec->packet_type = + TTUSB_DEC_PACKET_SECTION; dec->packet_state++; + } else if (dec->packet[0] == 0x00) { + dec->packet_type = + TTUSB_DEC_PACKET_EMPTY; + dec->packet_payload_length = 2; + dec->packet_state = 7; } else { + printk("%s: unknown packet type: " + "%02x%02x\n", __FUNCTION__, + dec->packet[0], dec->packet[1]); dec->packet_state = 0; } } @@ -532,13 +578,14 @@ static void ttusb_dec_process_urb_frame(struct ttusb_dec *dec, u8 *b, case 5: dec->packet[dec->packet_length++] = *b++; - if (dec->packet_type == PACKET_AV_PES && + if (dec->packet_type == TTUSB_DEC_PACKET_AV_PES && dec->packet_length == 8) { dec->packet_state++; dec->packet_payload_length = 8 + (dec->packet[6] << 8) + dec->packet[7]; - } else if (dec->packet_type == PACKET_SECTION && + } else if (dec->packet_type == + TTUSB_DEC_PACKET_SECTION && dec->packet_length == 5) { dec->packet_state++; dec->packet_payload_length = 5 + @@ -575,7 +622,7 @@ static void ttusb_dec_process_urb_frame(struct ttusb_dec *dec, u8 *b, dec->packet[dec->packet_length++] = *b++; - if (dec->packet_type == PACKET_SECTION && + if (dec->packet_type == TTUSB_DEC_PACKET_SECTION && dec->packet_payload_length % 2) tail++; @@ -690,7 +737,7 @@ static void ttusb_dec_setup_urbs(struct ttusb_dec *dec) urb->dev = dec->udev; urb->context = dec; urb->complete = ttusb_dec_process_urb; - urb->pipe = dec->stream_pipe; + urb->pipe = dec->in_pipe; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) urb->transfer_flags = URB_ISO_ASAP; urb->interval = 1; @@ -734,12 +781,30 @@ static void ttusb_dec_stop_iso_xfer(struct ttusb_dec *dec) * for a short period, so it's important not to call this function just before * trying to talk to it. */ -static void ttusb_dec_set_streaming_interface(struct ttusb_dec *dec) +static int ttusb_dec_set_interface(struct ttusb_dec *dec, + enum ttusb_dec_interface interface) { - if (!dec->interface) { - usb_set_interface(dec->udev, 0, 8); - dec->interface = 8; + int result = 0; + + if (interface != dec->interface) { + switch (interface) { + case TTUSB_DEC_INTERFACE_INITIAL: + result = usb_set_interface(dec->udev, 0, 0); + break; + case TTUSB_DEC_INTERFACE_IN: + result = usb_set_interface(dec->udev, 0, 7); + break; + case TTUSB_DEC_INTERFACE_OUT: + result = usb_set_interface(dec->udev, 0, 1); + break; + } + + if (result) + return result; + + dec->interface = interface; } + return 0; } static int ttusb_dec_start_iso_xfer(struct ttusb_dec *dec) @@ -754,6 +819,10 @@ static int ttusb_dec_start_iso_xfer(struct ttusb_dec *dec) if (!dec->iso_stream_count) { ttusb_dec_setup_urbs(dec); + dec->packet_state = 0; + dec->v_pes_postbytes = 0; + dec->next_packet_id = 0; + for (i = 0; i < ISO_BUF_COUNT; i++) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) if ((result = usb_submit_urb(dec->iso_urb[i], @@ -773,9 +842,6 @@ static int ttusb_dec_start_iso_xfer(struct ttusb_dec *dec) return result; } } - - dec->packet_state = 0; - dec->v_pes_postbytes = 0; } dec->iso_stream_count++; @@ -783,7 +849,7 @@ static int ttusb_dec_start_iso_xfer(struct ttusb_dec *dec) up(&dec->iso_sem); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - ttusb_dec_set_streaming_interface(dec); + ttusb_dec_set_interface(dec, TTUSB_DEC_INTERFACE_IN); #endif return 0; @@ -794,6 +860,7 @@ static int ttusb_dec_start_ts_feed(struct dvb_demux_feed *dvbdmxfeed) struct dvb_demux *dvbdmx = dvbdmxfeed->demux; struct ttusb_dec *dec = dvbdmx->priv; u8 b0[] = { 0x05 }; + int result = 0; dprintk("%s\n", __FUNCTION__); @@ -848,12 +915,12 @@ static int ttusb_dec_start_ts_feed(struct dvb_demux_feed *dvbdmxfeed) } - ttusb_dec_send_command(dec, 0x80, sizeof(b0), b0, NULL, NULL); + result = ttusb_dec_send_command(dec, 0x80, sizeof(b0), b0, NULL, NULL); + if (result) + return result; dec->av_pes_stream_count++; - ttusb_dec_start_iso_xfer(dec); - - return 0; + return ttusb_dec_start_iso_xfer(dec); } static int ttusb_dec_start_sec_feed(struct dvb_demux_feed *dvbdmxfeed) @@ -903,9 +970,7 @@ static int ttusb_dec_start_sec_feed(struct dvb_demux_feed *dvbdmxfeed) dvbdmxfeed->priv = finfo; dec->filter_stream_count++; - ttusb_dec_start_iso_xfer(dec); - - return 0; + return ttusb_dec_start_iso_xfer(dec); } return -EAGAIN; @@ -1078,13 +1143,15 @@ static void ttusb_dec_init_usb(struct ttusb_dec *dec) dec->command_pipe = usb_sndbulkpipe(dec->udev, COMMAND_PIPE); dec->result_pipe = usb_rcvbulkpipe(dec->udev, RESULT_PIPE); - dec->stream_pipe = usb_rcvisocpipe(dec->udev, STREAM_PIPE); + dec->in_pipe = usb_rcvisocpipe(dec->udev, IN_PIPE); + dec->out_pipe = usb_sndisocpipe(dec->udev, OUT_PIPE); ttusb_dec_alloc_iso_urbs(dec); } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) #include "dsp_dec2000t.h" +#include "dsp_dec2540t.h" #include "dsp_dec3000s.h" #endif @@ -1121,11 +1188,15 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec) #else switch (dec->model) { case TTUSB_DEC2000T: - case TTUSB_DEC2540T: firmware = &dsp_dec2000t[0]; firmware_size = sizeof(dsp_dec2000t); break; + case TTUSB_DEC2540T: + firmware = &dsp_dec2540t[0]; + firmware_size = sizeof(dsp_dec2540t); + break; + case TTUSB_DEC3000S: firmware = &dsp_dec3000s[0]; firmware_size = sizeof(dsp_dec3000s); @@ -1245,6 +1316,9 @@ static int ttusb_dec_init_stb(struct ttusb_dec *dec) break; } + if (version >= 0x01770000) + dec->can_playback = 1; + return 0; } } @@ -1698,7 +1772,7 @@ static int ttusb_dec_probe(struct usb_interface *intf, #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) return (void *)dec; #else - ttusb_dec_set_streaming_interface(dec); + ttusb_dec_set_interface(dec, TTUSB_DEC_INTERFACE_IN); return 0; #endif @@ -1801,3 +1875,5 @@ MODULE_DEVICE_TABLE(usb, ttusb_dec_table); MODULE_PARM(debug, "i"); MODULE_PARM_DESC(debug, "Debug level"); +MODULE_PARM(output_avpes, "i"); +MODULE_PARM_DESC(output_avpes, "Output AVPES from dvr device"); |