18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * TTUSB DEC Driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2003-2004 Alex Woods <linux-dvb@giblets.org> 68c2ecf20Sopenharmony_ci * IR support by Peter Beutner <p.beutner@gmx.net> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/list.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/pci.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 148c2ecf20Sopenharmony_ci#include <linux/usb.h> 158c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 168c2ecf20Sopenharmony_ci#include <linux/firmware.h> 178c2ecf20Sopenharmony_ci#include <linux/crc32.h> 188c2ecf20Sopenharmony_ci#include <linux/init.h> 198c2ecf20Sopenharmony_ci#include <linux/input.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <linux/mutex.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <media/dmxdev.h> 248c2ecf20Sopenharmony_ci#include <media/dvb_demux.h> 258c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h> 268c2ecf20Sopenharmony_ci#include <media/dvb_net.h> 278c2ecf20Sopenharmony_ci#include "ttusbdecfe.h" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic int debug; 308c2ecf20Sopenharmony_cistatic int output_pva; 318c2ecf20Sopenharmony_cistatic int enable_rc; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cimodule_param(debug, int, 0644); 348c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); 358c2ecf20Sopenharmony_cimodule_param(output_pva, int, 0444); 368c2ecf20Sopenharmony_ciMODULE_PARM_DESC(output_pva, "Output PVA from dvr device (default:off)"); 378c2ecf20Sopenharmony_cimodule_param(enable_rc, int, 0644); 388c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enable_rc, "Turn on/off IR remote control(default: off)"); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ciDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define dprintk if (debug) printk 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#define DRIVER_NAME "TechnoTrend/Hauppauge DEC USB" 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#define COMMAND_PIPE 0x03 478c2ecf20Sopenharmony_ci#define RESULT_PIPE 0x04 488c2ecf20Sopenharmony_ci#define IN_PIPE 0x08 498c2ecf20Sopenharmony_ci#define OUT_PIPE 0x07 508c2ecf20Sopenharmony_ci#define IRQ_PIPE 0x0A 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#define COMMAND_PACKET_SIZE 0x3c 538c2ecf20Sopenharmony_ci#define ARM_PACKET_SIZE 0x1000 548c2ecf20Sopenharmony_ci#define IRQ_PACKET_SIZE 0x8 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#define ISO_BUF_COUNT 0x04 578c2ecf20Sopenharmony_ci#define FRAMES_PER_ISO_BUF 0x04 588c2ecf20Sopenharmony_ci#define ISO_FRAME_SIZE 0x0380 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#define MAX_PVA_LENGTH 6144 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cienum ttusb_dec_model { 638c2ecf20Sopenharmony_ci TTUSB_DEC2000T, 648c2ecf20Sopenharmony_ci TTUSB_DEC2540T, 658c2ecf20Sopenharmony_ci TTUSB_DEC3000S 668c2ecf20Sopenharmony_ci}; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cienum ttusb_dec_packet_type { 698c2ecf20Sopenharmony_ci TTUSB_DEC_PACKET_PVA, 708c2ecf20Sopenharmony_ci TTUSB_DEC_PACKET_SECTION, 718c2ecf20Sopenharmony_ci TTUSB_DEC_PACKET_EMPTY 728c2ecf20Sopenharmony_ci}; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cienum ttusb_dec_interface { 758c2ecf20Sopenharmony_ci TTUSB_DEC_INTERFACE_INITIAL, 768c2ecf20Sopenharmony_ci TTUSB_DEC_INTERFACE_IN, 778c2ecf20Sopenharmony_ci TTUSB_DEC_INTERFACE_OUT 788c2ecf20Sopenharmony_ci}; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_citypedef int (dvb_filter_pes2ts_cb_t) (void *, unsigned char *); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistruct dvb_filter_pes2ts { 838c2ecf20Sopenharmony_ci unsigned char buf[188]; 848c2ecf20Sopenharmony_ci unsigned char cc; 858c2ecf20Sopenharmony_ci dvb_filter_pes2ts_cb_t *cb; 868c2ecf20Sopenharmony_ci void *priv; 878c2ecf20Sopenharmony_ci}; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistruct ttusb_dec { 908c2ecf20Sopenharmony_ci enum ttusb_dec_model model; 918c2ecf20Sopenharmony_ci char *model_name; 928c2ecf20Sopenharmony_ci char *firmware_name; 938c2ecf20Sopenharmony_ci int can_playback; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci /* DVB bits */ 968c2ecf20Sopenharmony_ci struct dvb_adapter adapter; 978c2ecf20Sopenharmony_ci struct dmxdev dmxdev; 988c2ecf20Sopenharmony_ci struct dvb_demux demux; 998c2ecf20Sopenharmony_ci struct dmx_frontend frontend; 1008c2ecf20Sopenharmony_ci struct dvb_net dvb_net; 1018c2ecf20Sopenharmony_ci struct dvb_frontend* fe; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci u16 pid[DMX_PES_OTHER]; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci /* USB bits */ 1068c2ecf20Sopenharmony_ci struct usb_device *udev; 1078c2ecf20Sopenharmony_ci u8 trans_count; 1088c2ecf20Sopenharmony_ci unsigned int command_pipe; 1098c2ecf20Sopenharmony_ci unsigned int result_pipe; 1108c2ecf20Sopenharmony_ci unsigned int in_pipe; 1118c2ecf20Sopenharmony_ci unsigned int out_pipe; 1128c2ecf20Sopenharmony_ci unsigned int irq_pipe; 1138c2ecf20Sopenharmony_ci enum ttusb_dec_interface interface; 1148c2ecf20Sopenharmony_ci struct mutex usb_mutex; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci void *irq_buffer; 1178c2ecf20Sopenharmony_ci struct urb *irq_urb; 1188c2ecf20Sopenharmony_ci dma_addr_t irq_dma_handle; 1198c2ecf20Sopenharmony_ci void *iso_buffer; 1208c2ecf20Sopenharmony_ci struct urb *iso_urb[ISO_BUF_COUNT]; 1218c2ecf20Sopenharmony_ci int iso_stream_count; 1228c2ecf20Sopenharmony_ci struct mutex iso_mutex; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci u8 packet[MAX_PVA_LENGTH + 4]; 1258c2ecf20Sopenharmony_ci enum ttusb_dec_packet_type packet_type; 1268c2ecf20Sopenharmony_ci int packet_state; 1278c2ecf20Sopenharmony_ci int packet_length; 1288c2ecf20Sopenharmony_ci int packet_payload_length; 1298c2ecf20Sopenharmony_ci u16 next_packet_id; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci int pva_stream_count; 1328c2ecf20Sopenharmony_ci int filter_stream_count; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci struct dvb_filter_pes2ts a_pes2ts; 1358c2ecf20Sopenharmony_ci struct dvb_filter_pes2ts v_pes2ts; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci u8 v_pes[16 + MAX_PVA_LENGTH]; 1388c2ecf20Sopenharmony_ci int v_pes_length; 1398c2ecf20Sopenharmony_ci int v_pes_postbytes; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci struct list_head urb_frame_list; 1428c2ecf20Sopenharmony_ci struct tasklet_struct urb_tasklet; 1438c2ecf20Sopenharmony_ci spinlock_t urb_frame_list_lock; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci struct dvb_demux_filter *audio_filter; 1468c2ecf20Sopenharmony_ci struct dvb_demux_filter *video_filter; 1478c2ecf20Sopenharmony_ci struct list_head filter_info_list; 1488c2ecf20Sopenharmony_ci spinlock_t filter_info_list_lock; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci struct input_dev *rc_input_dev; 1518c2ecf20Sopenharmony_ci char rc_phys[64]; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci int active; /* Loaded successfully */ 1548c2ecf20Sopenharmony_ci}; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistruct urb_frame { 1578c2ecf20Sopenharmony_ci u8 data[ISO_FRAME_SIZE]; 1588c2ecf20Sopenharmony_ci int length; 1598c2ecf20Sopenharmony_ci struct list_head urb_frame_list; 1608c2ecf20Sopenharmony_ci}; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistruct filter_info { 1638c2ecf20Sopenharmony_ci u8 stream_id; 1648c2ecf20Sopenharmony_ci struct dvb_demux_filter *filter; 1658c2ecf20Sopenharmony_ci struct list_head filter_info_list; 1668c2ecf20Sopenharmony_ci}; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic u16 rc_keys[] = { 1698c2ecf20Sopenharmony_ci KEY_POWER, 1708c2ecf20Sopenharmony_ci KEY_MUTE, 1718c2ecf20Sopenharmony_ci KEY_1, 1728c2ecf20Sopenharmony_ci KEY_2, 1738c2ecf20Sopenharmony_ci KEY_3, 1748c2ecf20Sopenharmony_ci KEY_4, 1758c2ecf20Sopenharmony_ci KEY_5, 1768c2ecf20Sopenharmony_ci KEY_6, 1778c2ecf20Sopenharmony_ci KEY_7, 1788c2ecf20Sopenharmony_ci KEY_8, 1798c2ecf20Sopenharmony_ci KEY_9, 1808c2ecf20Sopenharmony_ci KEY_0, 1818c2ecf20Sopenharmony_ci KEY_CHANNELUP, 1828c2ecf20Sopenharmony_ci KEY_VOLUMEDOWN, 1838c2ecf20Sopenharmony_ci KEY_OK, 1848c2ecf20Sopenharmony_ci KEY_VOLUMEUP, 1858c2ecf20Sopenharmony_ci KEY_CHANNELDOWN, 1868c2ecf20Sopenharmony_ci KEY_PREVIOUS, 1878c2ecf20Sopenharmony_ci KEY_ESC, 1888c2ecf20Sopenharmony_ci KEY_RED, 1898c2ecf20Sopenharmony_ci KEY_GREEN, 1908c2ecf20Sopenharmony_ci KEY_YELLOW, 1918c2ecf20Sopenharmony_ci KEY_BLUE, 1928c2ecf20Sopenharmony_ci KEY_OPTION, 1938c2ecf20Sopenharmony_ci KEY_M, 1948c2ecf20Sopenharmony_ci KEY_RADIO 1958c2ecf20Sopenharmony_ci}; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, 1988c2ecf20Sopenharmony_ci unsigned short pid, 1998c2ecf20Sopenharmony_ci dvb_filter_pes2ts_cb_t *cb, void *priv) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci unsigned char *buf=p2ts->buf; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci buf[0]=0x47; 2048c2ecf20Sopenharmony_ci buf[1]=(pid>>8); 2058c2ecf20Sopenharmony_ci buf[2]=pid&0xff; 2068c2ecf20Sopenharmony_ci p2ts->cc=0; 2078c2ecf20Sopenharmony_ci p2ts->cb=cb; 2088c2ecf20Sopenharmony_ci p2ts->priv=priv; 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, 2128c2ecf20Sopenharmony_ci unsigned char *pes, int len, int payload_start) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci unsigned char *buf=p2ts->buf; 2158c2ecf20Sopenharmony_ci int ret=0, rest; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci //len=6+((pes[4]<<8)|pes[5]); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if (payload_start) 2208c2ecf20Sopenharmony_ci buf[1]|=0x40; 2218c2ecf20Sopenharmony_ci else 2228c2ecf20Sopenharmony_ci buf[1]&=~0x40; 2238c2ecf20Sopenharmony_ci while (len>=184) { 2248c2ecf20Sopenharmony_ci buf[3]=0x10|((p2ts->cc++)&0x0f); 2258c2ecf20Sopenharmony_ci memcpy(buf+4, pes, 184); 2268c2ecf20Sopenharmony_ci if ((ret=p2ts->cb(p2ts->priv, buf))) 2278c2ecf20Sopenharmony_ci return ret; 2288c2ecf20Sopenharmony_ci len-=184; pes+=184; 2298c2ecf20Sopenharmony_ci buf[1]&=~0x40; 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci if (!len) 2328c2ecf20Sopenharmony_ci return 0; 2338c2ecf20Sopenharmony_ci buf[3]=0x30|((p2ts->cc++)&0x0f); 2348c2ecf20Sopenharmony_ci rest=183-len; 2358c2ecf20Sopenharmony_ci if (rest) { 2368c2ecf20Sopenharmony_ci buf[5]=0x00; 2378c2ecf20Sopenharmony_ci if (rest-1) 2388c2ecf20Sopenharmony_ci memset(buf+6, 0xff, rest-1); 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci buf[4]=rest; 2418c2ecf20Sopenharmony_ci memcpy(buf+5+rest, pes, len); 2428c2ecf20Sopenharmony_ci return p2ts->cb(p2ts->priv, buf); 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistatic void ttusb_dec_set_model(struct ttusb_dec *dec, 2468c2ecf20Sopenharmony_ci enum ttusb_dec_model model); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_cistatic void ttusb_dec_handle_irq( struct urb *urb) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci struct ttusb_dec *dec = urb->context; 2518c2ecf20Sopenharmony_ci char *buffer = dec->irq_buffer; 2528c2ecf20Sopenharmony_ci int retval; 2538c2ecf20Sopenharmony_ci int index = buffer[4]; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci switch(urb->status) { 2568c2ecf20Sopenharmony_ci case 0: /*success*/ 2578c2ecf20Sopenharmony_ci break; 2588c2ecf20Sopenharmony_ci case -ECONNRESET: 2598c2ecf20Sopenharmony_ci case -ENOENT: 2608c2ecf20Sopenharmony_ci case -ESHUTDOWN: 2618c2ecf20Sopenharmony_ci case -ETIME: 2628c2ecf20Sopenharmony_ci /* this urb is dead, cleanup */ 2638c2ecf20Sopenharmony_ci dprintk("%s:urb shutting down with status: %d\n", 2648c2ecf20Sopenharmony_ci __func__, urb->status); 2658c2ecf20Sopenharmony_ci return; 2668c2ecf20Sopenharmony_ci default: 2678c2ecf20Sopenharmony_ci dprintk("%s:nonzero status received: %d\n", 2688c2ecf20Sopenharmony_ci __func__,urb->status); 2698c2ecf20Sopenharmony_ci goto exit; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if ((buffer[0] == 0x1) && (buffer[2] == 0x15)) { 2738c2ecf20Sopenharmony_ci /* 2748c2ecf20Sopenharmony_ci * IR - Event 2758c2ecf20Sopenharmony_ci * 2768c2ecf20Sopenharmony_ci * this is an fact a bit too simple implementation; 2778c2ecf20Sopenharmony_ci * the box also reports a keyrepeat signal 2788c2ecf20Sopenharmony_ci * (with buffer[3] == 0x40) in an interval of ~100ms. 2798c2ecf20Sopenharmony_ci * But to handle this correctly we had to imlemenent some 2808c2ecf20Sopenharmony_ci * kind of timer which signals a 'key up' event if no 2818c2ecf20Sopenharmony_ci * keyrepeat signal is received for lets say 200ms. 2828c2ecf20Sopenharmony_ci * this should/could be added later ... 2838c2ecf20Sopenharmony_ci * for now lets report each signal as a key down and up 2848c2ecf20Sopenharmony_ci */ 2858c2ecf20Sopenharmony_ci if (index - 1 < ARRAY_SIZE(rc_keys)) { 2868c2ecf20Sopenharmony_ci dprintk("%s:rc signal:%d\n", __func__, index); 2878c2ecf20Sopenharmony_ci input_report_key(dec->rc_input_dev, rc_keys[index - 1], 1); 2888c2ecf20Sopenharmony_ci input_sync(dec->rc_input_dev); 2898c2ecf20Sopenharmony_ci input_report_key(dec->rc_input_dev, rc_keys[index - 1], 0); 2908c2ecf20Sopenharmony_ci input_sync(dec->rc_input_dev); 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ciexit: 2958c2ecf20Sopenharmony_ci retval = usb_submit_urb(urb, GFP_ATOMIC); 2968c2ecf20Sopenharmony_ci if (retval) 2978c2ecf20Sopenharmony_ci printk("%s - usb_commit_urb failed with result: %d\n", 2988c2ecf20Sopenharmony_ci __func__, retval); 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic u16 crc16(u16 crc, const u8 *buf, size_t len) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci u16 tmp; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci while (len--) { 3068c2ecf20Sopenharmony_ci crc ^= *buf++; 3078c2ecf20Sopenharmony_ci crc ^= (u8)crc >> 4; 3088c2ecf20Sopenharmony_ci tmp = (u8)crc; 3098c2ecf20Sopenharmony_ci crc ^= (tmp ^ (tmp << 1)) << 4; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci return crc; 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command, 3158c2ecf20Sopenharmony_ci int param_length, const u8 params[], 3168c2ecf20Sopenharmony_ci int *result_length, u8 cmd_result[]) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci int result, actual_len; 3198c2ecf20Sopenharmony_ci u8 *b; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci b = kzalloc(COMMAND_PACKET_SIZE + 4, GFP_KERNEL); 3248c2ecf20Sopenharmony_ci if (!b) 3258c2ecf20Sopenharmony_ci return -ENOMEM; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci if ((result = mutex_lock_interruptible(&dec->usb_mutex))) { 3288c2ecf20Sopenharmony_ci kfree(b); 3298c2ecf20Sopenharmony_ci printk("%s: Failed to lock usb mutex.\n", __func__); 3308c2ecf20Sopenharmony_ci return result; 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci b[0] = 0xaa; 3348c2ecf20Sopenharmony_ci b[1] = ++dec->trans_count; 3358c2ecf20Sopenharmony_ci b[2] = command; 3368c2ecf20Sopenharmony_ci b[3] = param_length; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci if (params) 3398c2ecf20Sopenharmony_ci memcpy(&b[4], params, param_length); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (debug) { 3428c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: command: %*ph\n", 3438c2ecf20Sopenharmony_ci __func__, param_length, b); 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci result = usb_bulk_msg(dec->udev, dec->command_pipe, b, 3478c2ecf20Sopenharmony_ci COMMAND_PACKET_SIZE + 4, &actual_len, 1000); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci if (result) { 3508c2ecf20Sopenharmony_ci printk("%s: command bulk message failed: error %d\n", 3518c2ecf20Sopenharmony_ci __func__, result); 3528c2ecf20Sopenharmony_ci mutex_unlock(&dec->usb_mutex); 3538c2ecf20Sopenharmony_ci kfree(b); 3548c2ecf20Sopenharmony_ci return result; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci result = usb_bulk_msg(dec->udev, dec->result_pipe, b, 3588c2ecf20Sopenharmony_ci COMMAND_PACKET_SIZE + 4, &actual_len, 1000); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci if (result) { 3618c2ecf20Sopenharmony_ci printk("%s: result bulk message failed: error %d\n", 3628c2ecf20Sopenharmony_ci __func__, result); 3638c2ecf20Sopenharmony_ci mutex_unlock(&dec->usb_mutex); 3648c2ecf20Sopenharmony_ci kfree(b); 3658c2ecf20Sopenharmony_ci return result; 3668c2ecf20Sopenharmony_ci } else { 3678c2ecf20Sopenharmony_ci if (debug) { 3688c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: result: %*ph\n", 3698c2ecf20Sopenharmony_ci __func__, actual_len, b); 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci if (result_length) 3738c2ecf20Sopenharmony_ci *result_length = b[3]; 3748c2ecf20Sopenharmony_ci if (cmd_result && b[3] > 0) 3758c2ecf20Sopenharmony_ci memcpy(cmd_result, &b[4], b[3]); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci mutex_unlock(&dec->usb_mutex); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci kfree(b); 3808c2ecf20Sopenharmony_ci return 0; 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_cistatic int ttusb_dec_get_stb_state (struct ttusb_dec *dec, unsigned int *mode, 3858c2ecf20Sopenharmony_ci unsigned int *model, unsigned int *version) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci u8 c[COMMAND_PACKET_SIZE]; 3888c2ecf20Sopenharmony_ci int c_length; 3898c2ecf20Sopenharmony_ci int result; 3908c2ecf20Sopenharmony_ci __be32 tmp; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci result = ttusb_dec_send_command(dec, 0x08, 0, NULL, &c_length, c); 3958c2ecf20Sopenharmony_ci if (result) 3968c2ecf20Sopenharmony_ci return result; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci if (c_length >= 0x0c) { 3998c2ecf20Sopenharmony_ci if (mode != NULL) { 4008c2ecf20Sopenharmony_ci memcpy(&tmp, c, 4); 4018c2ecf20Sopenharmony_ci *mode = ntohl(tmp); 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci if (model != NULL) { 4048c2ecf20Sopenharmony_ci memcpy(&tmp, &c[4], 4); 4058c2ecf20Sopenharmony_ci *model = ntohl(tmp); 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci if (version != NULL) { 4088c2ecf20Sopenharmony_ci memcpy(&tmp, &c[8], 4); 4098c2ecf20Sopenharmony_ci *version = ntohl(tmp); 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci return 0; 4128c2ecf20Sopenharmony_ci } else { 4138c2ecf20Sopenharmony_ci return -ENOENT; 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cistatic int ttusb_dec_audio_pes2ts_cb(void *priv, unsigned char *data) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci struct ttusb_dec *dec = priv; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci dec->audio_filter->feed->cb.ts(data, 188, NULL, 0, 4228c2ecf20Sopenharmony_ci &dec->audio_filter->feed->feed.ts, NULL); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci return 0; 4258c2ecf20Sopenharmony_ci} 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_cistatic int ttusb_dec_video_pes2ts_cb(void *priv, unsigned char *data) 4288c2ecf20Sopenharmony_ci{ 4298c2ecf20Sopenharmony_ci struct ttusb_dec *dec = priv; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci dec->video_filter->feed->cb.ts(data, 188, NULL, 0, 4328c2ecf20Sopenharmony_ci &dec->video_filter->feed->feed.ts, NULL); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci return 0; 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_cistatic void ttusb_dec_set_pids(struct ttusb_dec *dec) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci u8 b[] = { 0x00, 0x00, 0x00, 0x00, 4408c2ecf20Sopenharmony_ci 0x00, 0x00, 0xff, 0xff, 4418c2ecf20Sopenharmony_ci 0xff, 0xff, 0xff, 0xff }; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci __be16 pcr = htons(dec->pid[DMX_PES_PCR]); 4448c2ecf20Sopenharmony_ci __be16 audio = htons(dec->pid[DMX_PES_AUDIO]); 4458c2ecf20Sopenharmony_ci __be16 video = htons(dec->pid[DMX_PES_VIDEO]); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci memcpy(&b[0], &pcr, 2); 4508c2ecf20Sopenharmony_ci memcpy(&b[2], &audio, 2); 4518c2ecf20Sopenharmony_ci memcpy(&b[4], &video, 2); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci ttusb_dec_send_command(dec, 0x50, sizeof(b), b, NULL, NULL); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci dvb_filter_pes2ts_init(&dec->a_pes2ts, dec->pid[DMX_PES_AUDIO], 4568c2ecf20Sopenharmony_ci ttusb_dec_audio_pes2ts_cb, dec); 4578c2ecf20Sopenharmony_ci dvb_filter_pes2ts_init(&dec->v_pes2ts, dec->pid[DMX_PES_VIDEO], 4588c2ecf20Sopenharmony_ci ttusb_dec_video_pes2ts_cb, dec); 4598c2ecf20Sopenharmony_ci dec->v_pes_length = 0; 4608c2ecf20Sopenharmony_ci dec->v_pes_postbytes = 0; 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_cistatic void ttusb_dec_process_pva(struct ttusb_dec *dec, u8 *pva, int length) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci if (length < 8) { 4668c2ecf20Sopenharmony_ci printk("%s: packet too short - discarding\n", __func__); 4678c2ecf20Sopenharmony_ci return; 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci if (length > 8 + MAX_PVA_LENGTH) { 4718c2ecf20Sopenharmony_ci printk("%s: packet too long - discarding\n", __func__); 4728c2ecf20Sopenharmony_ci return; 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci switch (pva[2]) { 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci case 0x01: { /* VideoStream */ 4788c2ecf20Sopenharmony_ci int prebytes = pva[5] & 0x03; 4798c2ecf20Sopenharmony_ci int postbytes = (pva[5] & 0x0c) >> 2; 4808c2ecf20Sopenharmony_ci __be16 v_pes_payload_length; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci if (output_pva) { 4838c2ecf20Sopenharmony_ci dec->video_filter->feed->cb.ts(pva, length, NULL, 0, 4848c2ecf20Sopenharmony_ci &dec->video_filter->feed->feed.ts, NULL); 4858c2ecf20Sopenharmony_ci return; 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci if (dec->v_pes_postbytes > 0 && 4898c2ecf20Sopenharmony_ci dec->v_pes_postbytes == prebytes) { 4908c2ecf20Sopenharmony_ci memcpy(&dec->v_pes[dec->v_pes_length], 4918c2ecf20Sopenharmony_ci &pva[12], prebytes); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes, 4948c2ecf20Sopenharmony_ci dec->v_pes_length + prebytes, 1); 4958c2ecf20Sopenharmony_ci } 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci if (pva[5] & 0x10) { 4988c2ecf20Sopenharmony_ci dec->v_pes[7] = 0x80; 4998c2ecf20Sopenharmony_ci dec->v_pes[8] = 0x05; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci dec->v_pes[9] = 0x21 | ((pva[8] & 0xc0) >> 5); 5028c2ecf20Sopenharmony_ci dec->v_pes[10] = ((pva[8] & 0x3f) << 2) | 5038c2ecf20Sopenharmony_ci ((pva[9] & 0xc0) >> 6); 5048c2ecf20Sopenharmony_ci dec->v_pes[11] = 0x01 | 5058c2ecf20Sopenharmony_ci ((pva[9] & 0x3f) << 2) | 5068c2ecf20Sopenharmony_ci ((pva[10] & 0x80) >> 6); 5078c2ecf20Sopenharmony_ci dec->v_pes[12] = ((pva[10] & 0x7f) << 1) | 5088c2ecf20Sopenharmony_ci ((pva[11] & 0xc0) >> 7); 5098c2ecf20Sopenharmony_ci dec->v_pes[13] = 0x01 | ((pva[11] & 0x7f) << 1); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci memcpy(&dec->v_pes[14], &pva[12 + prebytes], 5128c2ecf20Sopenharmony_ci length - 12 - prebytes); 5138c2ecf20Sopenharmony_ci dec->v_pes_length = 14 + length - 12 - prebytes; 5148c2ecf20Sopenharmony_ci } else { 5158c2ecf20Sopenharmony_ci dec->v_pes[7] = 0x00; 5168c2ecf20Sopenharmony_ci dec->v_pes[8] = 0x00; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci memcpy(&dec->v_pes[9], &pva[8], length - 8); 5198c2ecf20Sopenharmony_ci dec->v_pes_length = 9 + length - 8; 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci dec->v_pes_postbytes = postbytes; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci if (dec->v_pes[9 + dec->v_pes[8]] == 0x00 && 5258c2ecf20Sopenharmony_ci dec->v_pes[10 + dec->v_pes[8]] == 0x00 && 5268c2ecf20Sopenharmony_ci dec->v_pes[11 + dec->v_pes[8]] == 0x01) 5278c2ecf20Sopenharmony_ci dec->v_pes[6] = 0x84; 5288c2ecf20Sopenharmony_ci else 5298c2ecf20Sopenharmony_ci dec->v_pes[6] = 0x80; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci v_pes_payload_length = htons(dec->v_pes_length - 6 + 5328c2ecf20Sopenharmony_ci postbytes); 5338c2ecf20Sopenharmony_ci memcpy(&dec->v_pes[4], &v_pes_payload_length, 2); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci if (postbytes == 0) 5368c2ecf20Sopenharmony_ci dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes, 5378c2ecf20Sopenharmony_ci dec->v_pes_length, 1); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci break; 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci case 0x02: /* MainAudioStream */ 5438c2ecf20Sopenharmony_ci if (output_pva) { 5448c2ecf20Sopenharmony_ci dec->audio_filter->feed->cb.ts(pva, length, NULL, 0, 5458c2ecf20Sopenharmony_ci &dec->audio_filter->feed->feed.ts, NULL); 5468c2ecf20Sopenharmony_ci return; 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci dvb_filter_pes2ts(&dec->a_pes2ts, &pva[8], length - 8, 5508c2ecf20Sopenharmony_ci pva[5] & 0x10); 5518c2ecf20Sopenharmony_ci break; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci default: 5548c2ecf20Sopenharmony_ci printk("%s: unknown PVA type: %02x.\n", __func__, 5558c2ecf20Sopenharmony_ci pva[2]); 5568c2ecf20Sopenharmony_ci break; 5578c2ecf20Sopenharmony_ci } 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_cistatic void ttusb_dec_process_filter(struct ttusb_dec *dec, u8 *packet, 5618c2ecf20Sopenharmony_ci int length) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci struct list_head *item; 5648c2ecf20Sopenharmony_ci struct filter_info *finfo; 5658c2ecf20Sopenharmony_ci struct dvb_demux_filter *filter = NULL; 5668c2ecf20Sopenharmony_ci unsigned long flags; 5678c2ecf20Sopenharmony_ci u8 sid; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci sid = packet[1]; 5708c2ecf20Sopenharmony_ci spin_lock_irqsave(&dec->filter_info_list_lock, flags); 5718c2ecf20Sopenharmony_ci for (item = dec->filter_info_list.next; item != &dec->filter_info_list; 5728c2ecf20Sopenharmony_ci item = item->next) { 5738c2ecf20Sopenharmony_ci finfo = list_entry(item, struct filter_info, filter_info_list); 5748c2ecf20Sopenharmony_ci if (finfo->stream_id == sid) { 5758c2ecf20Sopenharmony_ci filter = finfo->filter; 5768c2ecf20Sopenharmony_ci break; 5778c2ecf20Sopenharmony_ci } 5788c2ecf20Sopenharmony_ci } 5798c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dec->filter_info_list_lock, flags); 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci if (filter) 5828c2ecf20Sopenharmony_ci filter->feed->cb.sec(&packet[2], length - 2, NULL, 0, 5838c2ecf20Sopenharmony_ci &filter->filter, NULL); 5848c2ecf20Sopenharmony_ci} 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_cistatic void ttusb_dec_process_packet(struct ttusb_dec *dec) 5878c2ecf20Sopenharmony_ci{ 5888c2ecf20Sopenharmony_ci int i; 5898c2ecf20Sopenharmony_ci u16 csum = 0; 5908c2ecf20Sopenharmony_ci u16 packet_id; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci if (dec->packet_length % 2) { 5938c2ecf20Sopenharmony_ci printk("%s: odd sized packet - discarding\n", __func__); 5948c2ecf20Sopenharmony_ci return; 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci for (i = 0; i < dec->packet_length; i += 2) 5988c2ecf20Sopenharmony_ci csum ^= ((dec->packet[i] << 8) + dec->packet[i + 1]); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci if (csum) { 6018c2ecf20Sopenharmony_ci printk("%s: checksum failed - discarding\n", __func__); 6028c2ecf20Sopenharmony_ci return; 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci packet_id = dec->packet[dec->packet_length - 4] << 8; 6068c2ecf20Sopenharmony_ci packet_id += dec->packet[dec->packet_length - 3]; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci if ((packet_id != dec->next_packet_id) && dec->next_packet_id) { 6098c2ecf20Sopenharmony_ci printk("%s: warning: lost packets between %u and %u\n", 6108c2ecf20Sopenharmony_ci __func__, dec->next_packet_id - 1, packet_id); 6118c2ecf20Sopenharmony_ci } 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci if (packet_id == 0xffff) 6148c2ecf20Sopenharmony_ci dec->next_packet_id = 0x8000; 6158c2ecf20Sopenharmony_ci else 6168c2ecf20Sopenharmony_ci dec->next_packet_id = packet_id + 1; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci switch (dec->packet_type) { 6198c2ecf20Sopenharmony_ci case TTUSB_DEC_PACKET_PVA: 6208c2ecf20Sopenharmony_ci if (dec->pva_stream_count) 6218c2ecf20Sopenharmony_ci ttusb_dec_process_pva(dec, dec->packet, 6228c2ecf20Sopenharmony_ci dec->packet_payload_length); 6238c2ecf20Sopenharmony_ci break; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci case TTUSB_DEC_PACKET_SECTION: 6268c2ecf20Sopenharmony_ci if (dec->filter_stream_count) 6278c2ecf20Sopenharmony_ci ttusb_dec_process_filter(dec, dec->packet, 6288c2ecf20Sopenharmony_ci dec->packet_payload_length); 6298c2ecf20Sopenharmony_ci break; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci case TTUSB_DEC_PACKET_EMPTY: 6328c2ecf20Sopenharmony_ci break; 6338c2ecf20Sopenharmony_ci } 6348c2ecf20Sopenharmony_ci} 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_cistatic void swap_bytes(u8 *b, int length) 6378c2ecf20Sopenharmony_ci{ 6388c2ecf20Sopenharmony_ci length -= length % 2; 6398c2ecf20Sopenharmony_ci for (; length; b += 2, length -= 2) 6408c2ecf20Sopenharmony_ci swap(*b, *(b + 1)); 6418c2ecf20Sopenharmony_ci} 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_cistatic void ttusb_dec_process_urb_frame(struct ttusb_dec *dec, u8 *b, 6448c2ecf20Sopenharmony_ci int length) 6458c2ecf20Sopenharmony_ci{ 6468c2ecf20Sopenharmony_ci swap_bytes(b, length); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci while (length) { 6498c2ecf20Sopenharmony_ci switch (dec->packet_state) { 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci case 0: 6528c2ecf20Sopenharmony_ci case 1: 6538c2ecf20Sopenharmony_ci case 2: 6548c2ecf20Sopenharmony_ci if (*b++ == 0xaa) 6558c2ecf20Sopenharmony_ci dec->packet_state++; 6568c2ecf20Sopenharmony_ci else 6578c2ecf20Sopenharmony_ci dec->packet_state = 0; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci length--; 6608c2ecf20Sopenharmony_ci break; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci case 3: 6638c2ecf20Sopenharmony_ci if (*b == 0x00) { 6648c2ecf20Sopenharmony_ci dec->packet_state++; 6658c2ecf20Sopenharmony_ci dec->packet_length = 0; 6668c2ecf20Sopenharmony_ci } else if (*b != 0xaa) { 6678c2ecf20Sopenharmony_ci dec->packet_state = 0; 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci b++; 6718c2ecf20Sopenharmony_ci length--; 6728c2ecf20Sopenharmony_ci break; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci case 4: 6758c2ecf20Sopenharmony_ci dec->packet[dec->packet_length++] = *b++; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci if (dec->packet_length == 2) { 6788c2ecf20Sopenharmony_ci if (dec->packet[0] == 'A' && 6798c2ecf20Sopenharmony_ci dec->packet[1] == 'V') { 6808c2ecf20Sopenharmony_ci dec->packet_type = 6818c2ecf20Sopenharmony_ci TTUSB_DEC_PACKET_PVA; 6828c2ecf20Sopenharmony_ci dec->packet_state++; 6838c2ecf20Sopenharmony_ci } else if (dec->packet[0] == 'S') { 6848c2ecf20Sopenharmony_ci dec->packet_type = 6858c2ecf20Sopenharmony_ci TTUSB_DEC_PACKET_SECTION; 6868c2ecf20Sopenharmony_ci dec->packet_state++; 6878c2ecf20Sopenharmony_ci } else if (dec->packet[0] == 0x00) { 6888c2ecf20Sopenharmony_ci dec->packet_type = 6898c2ecf20Sopenharmony_ci TTUSB_DEC_PACKET_EMPTY; 6908c2ecf20Sopenharmony_ci dec->packet_payload_length = 2; 6918c2ecf20Sopenharmony_ci dec->packet_state = 7; 6928c2ecf20Sopenharmony_ci } else { 6938c2ecf20Sopenharmony_ci printk("%s: unknown packet type: %02x%02x\n", 6948c2ecf20Sopenharmony_ci __func__, 6958c2ecf20Sopenharmony_ci dec->packet[0], dec->packet[1]); 6968c2ecf20Sopenharmony_ci dec->packet_state = 0; 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci } 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci length--; 7018c2ecf20Sopenharmony_ci break; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci case 5: 7048c2ecf20Sopenharmony_ci dec->packet[dec->packet_length++] = *b++; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci if (dec->packet_type == TTUSB_DEC_PACKET_PVA && 7078c2ecf20Sopenharmony_ci dec->packet_length == 8) { 7088c2ecf20Sopenharmony_ci dec->packet_state++; 7098c2ecf20Sopenharmony_ci dec->packet_payload_length = 8 + 7108c2ecf20Sopenharmony_ci (dec->packet[6] << 8) + 7118c2ecf20Sopenharmony_ci dec->packet[7]; 7128c2ecf20Sopenharmony_ci } else if (dec->packet_type == 7138c2ecf20Sopenharmony_ci TTUSB_DEC_PACKET_SECTION && 7148c2ecf20Sopenharmony_ci dec->packet_length == 5) { 7158c2ecf20Sopenharmony_ci dec->packet_state++; 7168c2ecf20Sopenharmony_ci dec->packet_payload_length = 5 + 7178c2ecf20Sopenharmony_ci ((dec->packet[3] & 0x0f) << 8) + 7188c2ecf20Sopenharmony_ci dec->packet[4]; 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci length--; 7228c2ecf20Sopenharmony_ci break; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci case 6: { 7258c2ecf20Sopenharmony_ci int remainder = dec->packet_payload_length - 7268c2ecf20Sopenharmony_ci dec->packet_length; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci if (length >= remainder) { 7298c2ecf20Sopenharmony_ci memcpy(dec->packet + dec->packet_length, 7308c2ecf20Sopenharmony_ci b, remainder); 7318c2ecf20Sopenharmony_ci dec->packet_length += remainder; 7328c2ecf20Sopenharmony_ci b += remainder; 7338c2ecf20Sopenharmony_ci length -= remainder; 7348c2ecf20Sopenharmony_ci dec->packet_state++; 7358c2ecf20Sopenharmony_ci } else { 7368c2ecf20Sopenharmony_ci memcpy(&dec->packet[dec->packet_length], 7378c2ecf20Sopenharmony_ci b, length); 7388c2ecf20Sopenharmony_ci dec->packet_length += length; 7398c2ecf20Sopenharmony_ci length = 0; 7408c2ecf20Sopenharmony_ci } 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci break; 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci case 7: { 7468c2ecf20Sopenharmony_ci int tail = 4; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci dec->packet[dec->packet_length++] = *b++; 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci if (dec->packet_type == TTUSB_DEC_PACKET_SECTION && 7518c2ecf20Sopenharmony_ci dec->packet_payload_length % 2) 7528c2ecf20Sopenharmony_ci tail++; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci if (dec->packet_length == 7558c2ecf20Sopenharmony_ci dec->packet_payload_length + tail) { 7568c2ecf20Sopenharmony_ci ttusb_dec_process_packet(dec); 7578c2ecf20Sopenharmony_ci dec->packet_state = 0; 7588c2ecf20Sopenharmony_ci } 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci length--; 7618c2ecf20Sopenharmony_ci break; 7628c2ecf20Sopenharmony_ci } 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci default: 7658c2ecf20Sopenharmony_ci printk("%s: illegal packet state encountered.\n", 7668c2ecf20Sopenharmony_ci __func__); 7678c2ecf20Sopenharmony_ci dec->packet_state = 0; 7688c2ecf20Sopenharmony_ci } 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci} 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_cistatic void ttusb_dec_process_urb_frame_list(struct tasklet_struct *t) 7738c2ecf20Sopenharmony_ci{ 7748c2ecf20Sopenharmony_ci struct ttusb_dec *dec = from_tasklet(dec, t, urb_tasklet); 7758c2ecf20Sopenharmony_ci struct list_head *item; 7768c2ecf20Sopenharmony_ci struct urb_frame *frame; 7778c2ecf20Sopenharmony_ci unsigned long flags; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci while (1) { 7808c2ecf20Sopenharmony_ci spin_lock_irqsave(&dec->urb_frame_list_lock, flags); 7818c2ecf20Sopenharmony_ci if ((item = dec->urb_frame_list.next) != &dec->urb_frame_list) { 7828c2ecf20Sopenharmony_ci frame = list_entry(item, struct urb_frame, 7838c2ecf20Sopenharmony_ci urb_frame_list); 7848c2ecf20Sopenharmony_ci list_del(&frame->urb_frame_list); 7858c2ecf20Sopenharmony_ci } else { 7868c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dec->urb_frame_list_lock, 7878c2ecf20Sopenharmony_ci flags); 7888c2ecf20Sopenharmony_ci return; 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dec->urb_frame_list_lock, flags); 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci ttusb_dec_process_urb_frame(dec, frame->data, frame->length); 7938c2ecf20Sopenharmony_ci kfree(frame); 7948c2ecf20Sopenharmony_ci } 7958c2ecf20Sopenharmony_ci} 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_cistatic void ttusb_dec_process_urb(struct urb *urb) 7988c2ecf20Sopenharmony_ci{ 7998c2ecf20Sopenharmony_ci struct ttusb_dec *dec = urb->context; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci if (!urb->status) { 8028c2ecf20Sopenharmony_ci int i; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci for (i = 0; i < FRAMES_PER_ISO_BUF; i++) { 8058c2ecf20Sopenharmony_ci struct usb_iso_packet_descriptor *d; 8068c2ecf20Sopenharmony_ci u8 *b; 8078c2ecf20Sopenharmony_ci int length; 8088c2ecf20Sopenharmony_ci struct urb_frame *frame; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci d = &urb->iso_frame_desc[i]; 8118c2ecf20Sopenharmony_ci b = urb->transfer_buffer + d->offset; 8128c2ecf20Sopenharmony_ci length = d->actual_length; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci if ((frame = kmalloc(sizeof(struct urb_frame), 8158c2ecf20Sopenharmony_ci GFP_ATOMIC))) { 8168c2ecf20Sopenharmony_ci unsigned long flags; 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci memcpy(frame->data, b, length); 8198c2ecf20Sopenharmony_ci frame->length = length; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci spin_lock_irqsave(&dec->urb_frame_list_lock, 8228c2ecf20Sopenharmony_ci flags); 8238c2ecf20Sopenharmony_ci list_add_tail(&frame->urb_frame_list, 8248c2ecf20Sopenharmony_ci &dec->urb_frame_list); 8258c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dec->urb_frame_list_lock, 8268c2ecf20Sopenharmony_ci flags); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci tasklet_schedule(&dec->urb_tasklet); 8298c2ecf20Sopenharmony_ci } 8308c2ecf20Sopenharmony_ci } 8318c2ecf20Sopenharmony_ci } else { 8328c2ecf20Sopenharmony_ci /* -ENOENT is expected when unlinking urbs */ 8338c2ecf20Sopenharmony_ci if (urb->status != -ENOENT) 8348c2ecf20Sopenharmony_ci dprintk("%s: urb error: %d\n", __func__, 8358c2ecf20Sopenharmony_ci urb->status); 8368c2ecf20Sopenharmony_ci } 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci if (dec->iso_stream_count) 8398c2ecf20Sopenharmony_ci usb_submit_urb(urb, GFP_ATOMIC); 8408c2ecf20Sopenharmony_ci} 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_cistatic void ttusb_dec_setup_urbs(struct ttusb_dec *dec) 8438c2ecf20Sopenharmony_ci{ 8448c2ecf20Sopenharmony_ci int i, j, buffer_offset = 0; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci for (i = 0; i < ISO_BUF_COUNT; i++) { 8498c2ecf20Sopenharmony_ci int frame_offset = 0; 8508c2ecf20Sopenharmony_ci struct urb *urb = dec->iso_urb[i]; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci urb->dev = dec->udev; 8538c2ecf20Sopenharmony_ci urb->context = dec; 8548c2ecf20Sopenharmony_ci urb->complete = ttusb_dec_process_urb; 8558c2ecf20Sopenharmony_ci urb->pipe = dec->in_pipe; 8568c2ecf20Sopenharmony_ci urb->transfer_flags = URB_ISO_ASAP; 8578c2ecf20Sopenharmony_ci urb->interval = 1; 8588c2ecf20Sopenharmony_ci urb->number_of_packets = FRAMES_PER_ISO_BUF; 8598c2ecf20Sopenharmony_ci urb->transfer_buffer_length = ISO_FRAME_SIZE * 8608c2ecf20Sopenharmony_ci FRAMES_PER_ISO_BUF; 8618c2ecf20Sopenharmony_ci urb->transfer_buffer = dec->iso_buffer + buffer_offset; 8628c2ecf20Sopenharmony_ci buffer_offset += ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci for (j = 0; j < FRAMES_PER_ISO_BUF; j++) { 8658c2ecf20Sopenharmony_ci urb->iso_frame_desc[j].offset = frame_offset; 8668c2ecf20Sopenharmony_ci urb->iso_frame_desc[j].length = ISO_FRAME_SIZE; 8678c2ecf20Sopenharmony_ci frame_offset += ISO_FRAME_SIZE; 8688c2ecf20Sopenharmony_ci } 8698c2ecf20Sopenharmony_ci } 8708c2ecf20Sopenharmony_ci} 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_cistatic void ttusb_dec_stop_iso_xfer(struct ttusb_dec *dec) 8738c2ecf20Sopenharmony_ci{ 8748c2ecf20Sopenharmony_ci int i; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&dec->iso_mutex)) 8798c2ecf20Sopenharmony_ci return; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci dec->iso_stream_count--; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci if (!dec->iso_stream_count) { 8848c2ecf20Sopenharmony_ci for (i = 0; i < ISO_BUF_COUNT; i++) 8858c2ecf20Sopenharmony_ci usb_kill_urb(dec->iso_urb[i]); 8868c2ecf20Sopenharmony_ci } 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci mutex_unlock(&dec->iso_mutex); 8898c2ecf20Sopenharmony_ci} 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci/* Setting the interface of the DEC tends to take down the USB communications 8928c2ecf20Sopenharmony_ci * for a short period, so it's important not to call this function just before 8938c2ecf20Sopenharmony_ci * trying to talk to it. 8948c2ecf20Sopenharmony_ci */ 8958c2ecf20Sopenharmony_cistatic int ttusb_dec_set_interface(struct ttusb_dec *dec, 8968c2ecf20Sopenharmony_ci enum ttusb_dec_interface interface) 8978c2ecf20Sopenharmony_ci{ 8988c2ecf20Sopenharmony_ci int result = 0; 8998c2ecf20Sopenharmony_ci u8 b[] = { 0x05 }; 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci if (interface != dec->interface) { 9028c2ecf20Sopenharmony_ci switch (interface) { 9038c2ecf20Sopenharmony_ci case TTUSB_DEC_INTERFACE_INITIAL: 9048c2ecf20Sopenharmony_ci result = usb_set_interface(dec->udev, 0, 0); 9058c2ecf20Sopenharmony_ci break; 9068c2ecf20Sopenharmony_ci case TTUSB_DEC_INTERFACE_IN: 9078c2ecf20Sopenharmony_ci result = ttusb_dec_send_command(dec, 0x80, sizeof(b), 9088c2ecf20Sopenharmony_ci b, NULL, NULL); 9098c2ecf20Sopenharmony_ci if (result) 9108c2ecf20Sopenharmony_ci return result; 9118c2ecf20Sopenharmony_ci result = usb_set_interface(dec->udev, 0, 8); 9128c2ecf20Sopenharmony_ci break; 9138c2ecf20Sopenharmony_ci case TTUSB_DEC_INTERFACE_OUT: 9148c2ecf20Sopenharmony_ci result = usb_set_interface(dec->udev, 0, 1); 9158c2ecf20Sopenharmony_ci break; 9168c2ecf20Sopenharmony_ci } 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci if (result) 9198c2ecf20Sopenharmony_ci return result; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci dec->interface = interface; 9228c2ecf20Sopenharmony_ci } 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci return 0; 9258c2ecf20Sopenharmony_ci} 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_cistatic int ttusb_dec_start_iso_xfer(struct ttusb_dec *dec) 9288c2ecf20Sopenharmony_ci{ 9298c2ecf20Sopenharmony_ci int i, result; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&dec->iso_mutex)) 9348c2ecf20Sopenharmony_ci return -EAGAIN; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci if (!dec->iso_stream_count) { 9378c2ecf20Sopenharmony_ci ttusb_dec_setup_urbs(dec); 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci dec->packet_state = 0; 9408c2ecf20Sopenharmony_ci dec->v_pes_postbytes = 0; 9418c2ecf20Sopenharmony_ci dec->next_packet_id = 0; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci for (i = 0; i < ISO_BUF_COUNT; i++) { 9448c2ecf20Sopenharmony_ci if ((result = usb_submit_urb(dec->iso_urb[i], 9458c2ecf20Sopenharmony_ci GFP_ATOMIC))) { 9468c2ecf20Sopenharmony_ci printk("%s: failed urb submission %d: error %d\n", 9478c2ecf20Sopenharmony_ci __func__, i, result); 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci while (i) { 9508c2ecf20Sopenharmony_ci usb_kill_urb(dec->iso_urb[i - 1]); 9518c2ecf20Sopenharmony_ci i--; 9528c2ecf20Sopenharmony_ci } 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci mutex_unlock(&dec->iso_mutex); 9558c2ecf20Sopenharmony_ci return result; 9568c2ecf20Sopenharmony_ci } 9578c2ecf20Sopenharmony_ci } 9588c2ecf20Sopenharmony_ci } 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci dec->iso_stream_count++; 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci mutex_unlock(&dec->iso_mutex); 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci return 0; 9658c2ecf20Sopenharmony_ci} 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_cistatic int ttusb_dec_start_ts_feed(struct dvb_demux_feed *dvbdmxfeed) 9688c2ecf20Sopenharmony_ci{ 9698c2ecf20Sopenharmony_ci struct dvb_demux *dvbdmx = dvbdmxfeed->demux; 9708c2ecf20Sopenharmony_ci struct ttusb_dec *dec = dvbdmx->priv; 9718c2ecf20Sopenharmony_ci u8 b0[] = { 0x05 }; 9728c2ecf20Sopenharmony_ci int result = 0; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci dprintk(" ts_type:"); 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci if (dvbdmxfeed->ts_type & TS_DECODER) 9798c2ecf20Sopenharmony_ci dprintk(" TS_DECODER"); 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci if (dvbdmxfeed->ts_type & TS_PACKET) 9828c2ecf20Sopenharmony_ci dprintk(" TS_PACKET"); 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci if (dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY) 9858c2ecf20Sopenharmony_ci dprintk(" TS_PAYLOAD_ONLY"); 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci dprintk("\n"); 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci switch (dvbdmxfeed->pes_type) { 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci case DMX_PES_VIDEO: 9928c2ecf20Sopenharmony_ci dprintk(" pes_type: DMX_PES_VIDEO\n"); 9938c2ecf20Sopenharmony_ci dec->pid[DMX_PES_PCR] = dvbdmxfeed->pid; 9948c2ecf20Sopenharmony_ci dec->pid[DMX_PES_VIDEO] = dvbdmxfeed->pid; 9958c2ecf20Sopenharmony_ci dec->video_filter = dvbdmxfeed->filter; 9968c2ecf20Sopenharmony_ci ttusb_dec_set_pids(dec); 9978c2ecf20Sopenharmony_ci break; 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci case DMX_PES_AUDIO: 10008c2ecf20Sopenharmony_ci dprintk(" pes_type: DMX_PES_AUDIO\n"); 10018c2ecf20Sopenharmony_ci dec->pid[DMX_PES_AUDIO] = dvbdmxfeed->pid; 10028c2ecf20Sopenharmony_ci dec->audio_filter = dvbdmxfeed->filter; 10038c2ecf20Sopenharmony_ci ttusb_dec_set_pids(dec); 10048c2ecf20Sopenharmony_ci break; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci case DMX_PES_TELETEXT: 10078c2ecf20Sopenharmony_ci dec->pid[DMX_PES_TELETEXT] = dvbdmxfeed->pid; 10088c2ecf20Sopenharmony_ci dprintk(" pes_type: DMX_PES_TELETEXT(not supported)\n"); 10098c2ecf20Sopenharmony_ci return -ENOSYS; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci case DMX_PES_PCR: 10128c2ecf20Sopenharmony_ci dprintk(" pes_type: DMX_PES_PCR\n"); 10138c2ecf20Sopenharmony_ci dec->pid[DMX_PES_PCR] = dvbdmxfeed->pid; 10148c2ecf20Sopenharmony_ci ttusb_dec_set_pids(dec); 10158c2ecf20Sopenharmony_ci break; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci case DMX_PES_OTHER: 10188c2ecf20Sopenharmony_ci dprintk(" pes_type: DMX_PES_OTHER(not supported)\n"); 10198c2ecf20Sopenharmony_ci return -ENOSYS; 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci default: 10228c2ecf20Sopenharmony_ci dprintk(" pes_type: unknown (%d)\n", dvbdmxfeed->pes_type); 10238c2ecf20Sopenharmony_ci return -EINVAL; 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci } 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci result = ttusb_dec_send_command(dec, 0x80, sizeof(b0), b0, NULL, NULL); 10288c2ecf20Sopenharmony_ci if (result) 10298c2ecf20Sopenharmony_ci return result; 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci dec->pva_stream_count++; 10328c2ecf20Sopenharmony_ci return ttusb_dec_start_iso_xfer(dec); 10338c2ecf20Sopenharmony_ci} 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_cistatic int ttusb_dec_start_sec_feed(struct dvb_demux_feed *dvbdmxfeed) 10368c2ecf20Sopenharmony_ci{ 10378c2ecf20Sopenharmony_ci struct ttusb_dec *dec = dvbdmxfeed->demux->priv; 10388c2ecf20Sopenharmony_ci u8 b0[] = { 0x00, 0x00, 0x00, 0x01, 10398c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 10408c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 10418c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 10428c2ecf20Sopenharmony_ci 0x00, 0xff, 0x00, 0x00, 10438c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 10448c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 10458c2ecf20Sopenharmony_ci 0x00 }; 10468c2ecf20Sopenharmony_ci __be16 pid; 10478c2ecf20Sopenharmony_ci u8 c[COMMAND_PACKET_SIZE]; 10488c2ecf20Sopenharmony_ci int c_length; 10498c2ecf20Sopenharmony_ci int result; 10508c2ecf20Sopenharmony_ci struct filter_info *finfo; 10518c2ecf20Sopenharmony_ci unsigned long flags; 10528c2ecf20Sopenharmony_ci u8 x = 1; 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci pid = htons(dvbdmxfeed->pid); 10578c2ecf20Sopenharmony_ci memcpy(&b0[0], &pid, 2); 10588c2ecf20Sopenharmony_ci memcpy(&b0[4], &x, 1); 10598c2ecf20Sopenharmony_ci memcpy(&b0[5], &dvbdmxfeed->filter->filter.filter_value[0], 1); 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci result = ttusb_dec_send_command(dec, 0x60, sizeof(b0), b0, 10628c2ecf20Sopenharmony_ci &c_length, c); 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci if (!result) { 10658c2ecf20Sopenharmony_ci if (c_length == 2) { 10668c2ecf20Sopenharmony_ci if (!(finfo = kmalloc(sizeof(struct filter_info), 10678c2ecf20Sopenharmony_ci GFP_ATOMIC))) 10688c2ecf20Sopenharmony_ci return -ENOMEM; 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci finfo->stream_id = c[1]; 10718c2ecf20Sopenharmony_ci finfo->filter = dvbdmxfeed->filter; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci spin_lock_irqsave(&dec->filter_info_list_lock, flags); 10748c2ecf20Sopenharmony_ci list_add_tail(&finfo->filter_info_list, 10758c2ecf20Sopenharmony_ci &dec->filter_info_list); 10768c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dec->filter_info_list_lock, 10778c2ecf20Sopenharmony_ci flags); 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci dvbdmxfeed->priv = finfo; 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci dec->filter_stream_count++; 10828c2ecf20Sopenharmony_ci return ttusb_dec_start_iso_xfer(dec); 10838c2ecf20Sopenharmony_ci } 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci return -EAGAIN; 10868c2ecf20Sopenharmony_ci } else 10878c2ecf20Sopenharmony_ci return result; 10888c2ecf20Sopenharmony_ci} 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_cistatic int ttusb_dec_start_feed(struct dvb_demux_feed *dvbdmxfeed) 10918c2ecf20Sopenharmony_ci{ 10928c2ecf20Sopenharmony_ci struct dvb_demux *dvbdmx = dvbdmxfeed->demux; 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci if (!dvbdmx->dmx.frontend) 10978c2ecf20Sopenharmony_ci return -EINVAL; 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci dprintk(" pid: 0x%04X\n", dvbdmxfeed->pid); 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci switch (dvbdmxfeed->type) { 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci case DMX_TYPE_TS: 11048c2ecf20Sopenharmony_ci return ttusb_dec_start_ts_feed(dvbdmxfeed); 11058c2ecf20Sopenharmony_ci break; 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci case DMX_TYPE_SEC: 11088c2ecf20Sopenharmony_ci return ttusb_dec_start_sec_feed(dvbdmxfeed); 11098c2ecf20Sopenharmony_ci break; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci default: 11128c2ecf20Sopenharmony_ci dprintk(" type: unknown (%d)\n", dvbdmxfeed->type); 11138c2ecf20Sopenharmony_ci return -EINVAL; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci } 11168c2ecf20Sopenharmony_ci} 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_cistatic int ttusb_dec_stop_ts_feed(struct dvb_demux_feed *dvbdmxfeed) 11198c2ecf20Sopenharmony_ci{ 11208c2ecf20Sopenharmony_ci struct ttusb_dec *dec = dvbdmxfeed->demux->priv; 11218c2ecf20Sopenharmony_ci u8 b0[] = { 0x00 }; 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci ttusb_dec_send_command(dec, 0x81, sizeof(b0), b0, NULL, NULL); 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci dec->pva_stream_count--; 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci ttusb_dec_stop_iso_xfer(dec); 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci return 0; 11308c2ecf20Sopenharmony_ci} 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_cistatic int ttusb_dec_stop_sec_feed(struct dvb_demux_feed *dvbdmxfeed) 11338c2ecf20Sopenharmony_ci{ 11348c2ecf20Sopenharmony_ci struct ttusb_dec *dec = dvbdmxfeed->demux->priv; 11358c2ecf20Sopenharmony_ci u8 b0[] = { 0x00, 0x00 }; 11368c2ecf20Sopenharmony_ci struct filter_info *finfo = (struct filter_info *)dvbdmxfeed->priv; 11378c2ecf20Sopenharmony_ci unsigned long flags; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci b0[1] = finfo->stream_id; 11408c2ecf20Sopenharmony_ci spin_lock_irqsave(&dec->filter_info_list_lock, flags); 11418c2ecf20Sopenharmony_ci list_del(&finfo->filter_info_list); 11428c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dec->filter_info_list_lock, flags); 11438c2ecf20Sopenharmony_ci kfree(finfo); 11448c2ecf20Sopenharmony_ci ttusb_dec_send_command(dec, 0x62, sizeof(b0), b0, NULL, NULL); 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci dec->filter_stream_count--; 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci ttusb_dec_stop_iso_xfer(dec); 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci return 0; 11518c2ecf20Sopenharmony_ci} 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_cistatic int ttusb_dec_stop_feed(struct dvb_demux_feed *dvbdmxfeed) 11548c2ecf20Sopenharmony_ci{ 11558c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci switch (dvbdmxfeed->type) { 11588c2ecf20Sopenharmony_ci case DMX_TYPE_TS: 11598c2ecf20Sopenharmony_ci return ttusb_dec_stop_ts_feed(dvbdmxfeed); 11608c2ecf20Sopenharmony_ci break; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci case DMX_TYPE_SEC: 11638c2ecf20Sopenharmony_ci return ttusb_dec_stop_sec_feed(dvbdmxfeed); 11648c2ecf20Sopenharmony_ci break; 11658c2ecf20Sopenharmony_ci } 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci return 0; 11688c2ecf20Sopenharmony_ci} 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_cistatic void ttusb_dec_free_iso_urbs(struct ttusb_dec *dec) 11718c2ecf20Sopenharmony_ci{ 11728c2ecf20Sopenharmony_ci int i; 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci for (i = 0; i < ISO_BUF_COUNT; i++) 11778c2ecf20Sopenharmony_ci usb_free_urb(dec->iso_urb[i]); 11788c2ecf20Sopenharmony_ci kfree(dec->iso_buffer); 11798c2ecf20Sopenharmony_ci} 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_cistatic int ttusb_dec_alloc_iso_urbs(struct ttusb_dec *dec) 11828c2ecf20Sopenharmony_ci{ 11838c2ecf20Sopenharmony_ci int i; 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci dec->iso_buffer = kcalloc(FRAMES_PER_ISO_BUF * ISO_BUF_COUNT, 11888c2ecf20Sopenharmony_ci ISO_FRAME_SIZE, GFP_KERNEL); 11898c2ecf20Sopenharmony_ci if (!dec->iso_buffer) 11908c2ecf20Sopenharmony_ci return -ENOMEM; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci for (i = 0; i < ISO_BUF_COUNT; i++) { 11938c2ecf20Sopenharmony_ci struct urb *urb; 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci if (!(urb = usb_alloc_urb(FRAMES_PER_ISO_BUF, GFP_ATOMIC))) { 11968c2ecf20Sopenharmony_ci ttusb_dec_free_iso_urbs(dec); 11978c2ecf20Sopenharmony_ci return -ENOMEM; 11988c2ecf20Sopenharmony_ci } 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci dec->iso_urb[i] = urb; 12018c2ecf20Sopenharmony_ci } 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci ttusb_dec_setup_urbs(dec); 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci return 0; 12068c2ecf20Sopenharmony_ci} 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_cistatic void ttusb_dec_init_tasklet(struct ttusb_dec *dec) 12098c2ecf20Sopenharmony_ci{ 12108c2ecf20Sopenharmony_ci spin_lock_init(&dec->urb_frame_list_lock); 12118c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dec->urb_frame_list); 12128c2ecf20Sopenharmony_ci tasklet_setup(&dec->urb_tasklet, ttusb_dec_process_urb_frame_list); 12138c2ecf20Sopenharmony_ci} 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_cistatic int ttusb_init_rc( struct ttusb_dec *dec) 12168c2ecf20Sopenharmony_ci{ 12178c2ecf20Sopenharmony_ci struct input_dev *input_dev; 12188c2ecf20Sopenharmony_ci u8 b[] = { 0x00, 0x01 }; 12198c2ecf20Sopenharmony_ci int i; 12208c2ecf20Sopenharmony_ci int err; 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci usb_make_path(dec->udev, dec->rc_phys, sizeof(dec->rc_phys)); 12238c2ecf20Sopenharmony_ci strlcat(dec->rc_phys, "/input0", sizeof(dec->rc_phys)); 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci input_dev = input_allocate_device(); 12268c2ecf20Sopenharmony_ci if (!input_dev) 12278c2ecf20Sopenharmony_ci return -ENOMEM; 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci input_dev->name = "ttusb_dec remote control"; 12308c2ecf20Sopenharmony_ci input_dev->phys = dec->rc_phys; 12318c2ecf20Sopenharmony_ci input_dev->evbit[0] = BIT_MASK(EV_KEY); 12328c2ecf20Sopenharmony_ci input_dev->keycodesize = sizeof(u16); 12338c2ecf20Sopenharmony_ci input_dev->keycodemax = 0x1a; 12348c2ecf20Sopenharmony_ci input_dev->keycode = rc_keys; 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(rc_keys); i++) 12378c2ecf20Sopenharmony_ci set_bit(rc_keys[i], input_dev->keybit); 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci err = input_register_device(input_dev); 12408c2ecf20Sopenharmony_ci if (err) { 12418c2ecf20Sopenharmony_ci input_free_device(input_dev); 12428c2ecf20Sopenharmony_ci return err; 12438c2ecf20Sopenharmony_ci } 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci dec->rc_input_dev = input_dev; 12468c2ecf20Sopenharmony_ci if (usb_submit_urb(dec->irq_urb, GFP_KERNEL)) 12478c2ecf20Sopenharmony_ci printk("%s: usb_submit_urb failed\n",__func__); 12488c2ecf20Sopenharmony_ci /* enable irq pipe */ 12498c2ecf20Sopenharmony_ci ttusb_dec_send_command(dec,0xb0,sizeof(b),b,NULL,NULL); 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci return 0; 12528c2ecf20Sopenharmony_ci} 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_cistatic void ttusb_dec_init_v_pes(struct ttusb_dec *dec) 12558c2ecf20Sopenharmony_ci{ 12568c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci dec->v_pes[0] = 0x00; 12598c2ecf20Sopenharmony_ci dec->v_pes[1] = 0x00; 12608c2ecf20Sopenharmony_ci dec->v_pes[2] = 0x01; 12618c2ecf20Sopenharmony_ci dec->v_pes[3] = 0xe0; 12628c2ecf20Sopenharmony_ci} 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_cistatic int ttusb_dec_init_usb(struct ttusb_dec *dec) 12658c2ecf20Sopenharmony_ci{ 12668c2ecf20Sopenharmony_ci int result; 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci mutex_init(&dec->usb_mutex); 12718c2ecf20Sopenharmony_ci mutex_init(&dec->iso_mutex); 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci dec->command_pipe = usb_sndbulkpipe(dec->udev, COMMAND_PIPE); 12748c2ecf20Sopenharmony_ci dec->result_pipe = usb_rcvbulkpipe(dec->udev, RESULT_PIPE); 12758c2ecf20Sopenharmony_ci dec->in_pipe = usb_rcvisocpipe(dec->udev, IN_PIPE); 12768c2ecf20Sopenharmony_ci dec->out_pipe = usb_sndisocpipe(dec->udev, OUT_PIPE); 12778c2ecf20Sopenharmony_ci dec->irq_pipe = usb_rcvintpipe(dec->udev, IRQ_PIPE); 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci if(enable_rc) { 12808c2ecf20Sopenharmony_ci dec->irq_urb = usb_alloc_urb(0, GFP_KERNEL); 12818c2ecf20Sopenharmony_ci if(!dec->irq_urb) { 12828c2ecf20Sopenharmony_ci return -ENOMEM; 12838c2ecf20Sopenharmony_ci } 12848c2ecf20Sopenharmony_ci dec->irq_buffer = usb_alloc_coherent(dec->udev,IRQ_PACKET_SIZE, 12858c2ecf20Sopenharmony_ci GFP_KERNEL, &dec->irq_dma_handle); 12868c2ecf20Sopenharmony_ci if(!dec->irq_buffer) { 12878c2ecf20Sopenharmony_ci usb_free_urb(dec->irq_urb); 12888c2ecf20Sopenharmony_ci return -ENOMEM; 12898c2ecf20Sopenharmony_ci } 12908c2ecf20Sopenharmony_ci usb_fill_int_urb(dec->irq_urb, dec->udev,dec->irq_pipe, 12918c2ecf20Sopenharmony_ci dec->irq_buffer, IRQ_PACKET_SIZE, 12928c2ecf20Sopenharmony_ci ttusb_dec_handle_irq, dec, 1); 12938c2ecf20Sopenharmony_ci dec->irq_urb->transfer_dma = dec->irq_dma_handle; 12948c2ecf20Sopenharmony_ci dec->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 12958c2ecf20Sopenharmony_ci } 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci result = ttusb_dec_alloc_iso_urbs(dec); 12988c2ecf20Sopenharmony_ci if (result) { 12998c2ecf20Sopenharmony_ci usb_free_urb(dec->irq_urb); 13008c2ecf20Sopenharmony_ci usb_free_coherent(dec->udev, IRQ_PACKET_SIZE, 13018c2ecf20Sopenharmony_ci dec->irq_buffer, dec->irq_dma_handle); 13028c2ecf20Sopenharmony_ci } 13038c2ecf20Sopenharmony_ci return result; 13048c2ecf20Sopenharmony_ci} 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_cistatic int ttusb_dec_boot_dsp(struct ttusb_dec *dec) 13078c2ecf20Sopenharmony_ci{ 13088c2ecf20Sopenharmony_ci int i, j, actual_len, result, size, trans_count; 13098c2ecf20Sopenharmony_ci u8 b0[] = { 0x00, 0x00, 0x00, 0x00, 13108c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 13118c2ecf20Sopenharmony_ci 0x61, 0x00 }; 13128c2ecf20Sopenharmony_ci u8 b1[] = { 0x61 }; 13138c2ecf20Sopenharmony_ci u8 *b; 13148c2ecf20Sopenharmony_ci char idstring[21]; 13158c2ecf20Sopenharmony_ci const u8 *firmware = NULL; 13168c2ecf20Sopenharmony_ci size_t firmware_size = 0; 13178c2ecf20Sopenharmony_ci u16 firmware_csum = 0; 13188c2ecf20Sopenharmony_ci __be16 firmware_csum_ns; 13198c2ecf20Sopenharmony_ci __be32 firmware_size_nl; 13208c2ecf20Sopenharmony_ci u32 crc32_csum, crc32_check; 13218c2ecf20Sopenharmony_ci __be32 tmp; 13228c2ecf20Sopenharmony_ci const struct firmware *fw_entry = NULL; 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci result = request_firmware(&fw_entry, dec->firmware_name, &dec->udev->dev); 13278c2ecf20Sopenharmony_ci if (result) { 13288c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Firmware (%s) unavailable.\n", 13298c2ecf20Sopenharmony_ci __func__, dec->firmware_name); 13308c2ecf20Sopenharmony_ci return result; 13318c2ecf20Sopenharmony_ci } 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci firmware = fw_entry->data; 13348c2ecf20Sopenharmony_ci firmware_size = fw_entry->size; 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci if (firmware_size < 60) { 13378c2ecf20Sopenharmony_ci printk("%s: firmware size too small for DSP code (%zu < 60).\n", 13388c2ecf20Sopenharmony_ci __func__, firmware_size); 13398c2ecf20Sopenharmony_ci release_firmware(fw_entry); 13408c2ecf20Sopenharmony_ci return -ENOENT; 13418c2ecf20Sopenharmony_ci } 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci /* a 32 bit checksum over the first 56 bytes of the DSP Code is stored 13448c2ecf20Sopenharmony_ci at offset 56 of file, so use it to check if the firmware file is 13458c2ecf20Sopenharmony_ci valid. */ 13468c2ecf20Sopenharmony_ci crc32_csum = crc32(~0L, firmware, 56) ^ ~0L; 13478c2ecf20Sopenharmony_ci memcpy(&tmp, &firmware[56], 4); 13488c2ecf20Sopenharmony_ci crc32_check = ntohl(tmp); 13498c2ecf20Sopenharmony_ci if (crc32_csum != crc32_check) { 13508c2ecf20Sopenharmony_ci printk("%s: crc32 check of DSP code failed (calculated 0x%08x != 0x%08x in file), file invalid.\n", 13518c2ecf20Sopenharmony_ci __func__, crc32_csum, crc32_check); 13528c2ecf20Sopenharmony_ci release_firmware(fw_entry); 13538c2ecf20Sopenharmony_ci return -ENOENT; 13548c2ecf20Sopenharmony_ci } 13558c2ecf20Sopenharmony_ci memcpy(idstring, &firmware[36], 20); 13568c2ecf20Sopenharmony_ci idstring[20] = '\0'; 13578c2ecf20Sopenharmony_ci printk(KERN_INFO "ttusb_dec: found DSP code \"%s\".\n", idstring); 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci firmware_size_nl = htonl(firmware_size); 13608c2ecf20Sopenharmony_ci memcpy(b0, &firmware_size_nl, 4); 13618c2ecf20Sopenharmony_ci firmware_csum = crc16(~0, firmware, firmware_size) ^ ~0; 13628c2ecf20Sopenharmony_ci firmware_csum_ns = htons(firmware_csum); 13638c2ecf20Sopenharmony_ci memcpy(&b0[6], &firmware_csum_ns, 2); 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci result = ttusb_dec_send_command(dec, 0x41, sizeof(b0), b0, NULL, NULL); 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci if (result) { 13688c2ecf20Sopenharmony_ci release_firmware(fw_entry); 13698c2ecf20Sopenharmony_ci return result; 13708c2ecf20Sopenharmony_ci } 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci trans_count = 0; 13738c2ecf20Sopenharmony_ci j = 0; 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci b = kmalloc(ARM_PACKET_SIZE, GFP_KERNEL); 13768c2ecf20Sopenharmony_ci if (b == NULL) { 13778c2ecf20Sopenharmony_ci release_firmware(fw_entry); 13788c2ecf20Sopenharmony_ci return -ENOMEM; 13798c2ecf20Sopenharmony_ci } 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci for (i = 0; i < firmware_size; i += COMMAND_PACKET_SIZE) { 13828c2ecf20Sopenharmony_ci size = firmware_size - i; 13838c2ecf20Sopenharmony_ci if (size > COMMAND_PACKET_SIZE) 13848c2ecf20Sopenharmony_ci size = COMMAND_PACKET_SIZE; 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci b[j + 0] = 0xaa; 13878c2ecf20Sopenharmony_ci b[j + 1] = trans_count++; 13888c2ecf20Sopenharmony_ci b[j + 2] = 0xf0; 13898c2ecf20Sopenharmony_ci b[j + 3] = size; 13908c2ecf20Sopenharmony_ci memcpy(&b[j + 4], &firmware[i], size); 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci j += COMMAND_PACKET_SIZE + 4; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci if (j >= ARM_PACKET_SIZE) { 13958c2ecf20Sopenharmony_ci result = usb_bulk_msg(dec->udev, dec->command_pipe, b, 13968c2ecf20Sopenharmony_ci ARM_PACKET_SIZE, &actual_len, 13978c2ecf20Sopenharmony_ci 100); 13988c2ecf20Sopenharmony_ci j = 0; 13998c2ecf20Sopenharmony_ci } else if (size < COMMAND_PACKET_SIZE) { 14008c2ecf20Sopenharmony_ci result = usb_bulk_msg(dec->udev, dec->command_pipe, b, 14018c2ecf20Sopenharmony_ci j - COMMAND_PACKET_SIZE + size, 14028c2ecf20Sopenharmony_ci &actual_len, 100); 14038c2ecf20Sopenharmony_ci } 14048c2ecf20Sopenharmony_ci } 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci result = ttusb_dec_send_command(dec, 0x43, sizeof(b1), b1, NULL, NULL); 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci release_firmware(fw_entry); 14098c2ecf20Sopenharmony_ci kfree(b); 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci return result; 14128c2ecf20Sopenharmony_ci} 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_cistatic int ttusb_dec_init_stb(struct ttusb_dec *dec) 14158c2ecf20Sopenharmony_ci{ 14168c2ecf20Sopenharmony_ci int result; 14178c2ecf20Sopenharmony_ci unsigned int mode = 0, model = 0, version = 0; 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci result = ttusb_dec_get_stb_state(dec, &mode, &model, &version); 14228c2ecf20Sopenharmony_ci if (result) 14238c2ecf20Sopenharmony_ci return result; 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci if (!mode) { 14268c2ecf20Sopenharmony_ci if (version == 0xABCDEFAB) 14278c2ecf20Sopenharmony_ci printk(KERN_INFO "ttusb_dec: no version info in Firmware\n"); 14288c2ecf20Sopenharmony_ci else 14298c2ecf20Sopenharmony_ci printk(KERN_INFO "ttusb_dec: Firmware %x.%02x%c%c\n", 14308c2ecf20Sopenharmony_ci version >> 24, (version >> 16) & 0xff, 14318c2ecf20Sopenharmony_ci (version >> 8) & 0xff, version & 0xff); 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci result = ttusb_dec_boot_dsp(dec); 14348c2ecf20Sopenharmony_ci if (result) 14358c2ecf20Sopenharmony_ci return result; 14368c2ecf20Sopenharmony_ci } else { 14378c2ecf20Sopenharmony_ci /* We can't trust the USB IDs that some firmwares 14388c2ecf20Sopenharmony_ci give the box */ 14398c2ecf20Sopenharmony_ci switch (model) { 14408c2ecf20Sopenharmony_ci case 0x00070001: 14418c2ecf20Sopenharmony_ci case 0x00070008: 14428c2ecf20Sopenharmony_ci case 0x0007000c: 14438c2ecf20Sopenharmony_ci ttusb_dec_set_model(dec, TTUSB_DEC3000S); 14448c2ecf20Sopenharmony_ci break; 14458c2ecf20Sopenharmony_ci case 0x00070009: 14468c2ecf20Sopenharmony_ci case 0x00070013: 14478c2ecf20Sopenharmony_ci ttusb_dec_set_model(dec, TTUSB_DEC2000T); 14488c2ecf20Sopenharmony_ci break; 14498c2ecf20Sopenharmony_ci case 0x00070011: 14508c2ecf20Sopenharmony_ci ttusb_dec_set_model(dec, TTUSB_DEC2540T); 14518c2ecf20Sopenharmony_ci break; 14528c2ecf20Sopenharmony_ci default: 14538c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: unknown model returned by firmware (%08x) - please report\n", 14548c2ecf20Sopenharmony_ci __func__, model); 14558c2ecf20Sopenharmony_ci return -ENOENT; 14568c2ecf20Sopenharmony_ci } 14578c2ecf20Sopenharmony_ci if (version >= 0x01770000) 14588c2ecf20Sopenharmony_ci dec->can_playback = 1; 14598c2ecf20Sopenharmony_ci } 14608c2ecf20Sopenharmony_ci return 0; 14618c2ecf20Sopenharmony_ci} 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_cistatic int ttusb_dec_init_dvb(struct ttusb_dec *dec) 14648c2ecf20Sopenharmony_ci{ 14658c2ecf20Sopenharmony_ci int result; 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci if ((result = dvb_register_adapter(&dec->adapter, 14708c2ecf20Sopenharmony_ci dec->model_name, THIS_MODULE, 14718c2ecf20Sopenharmony_ci &dec->udev->dev, 14728c2ecf20Sopenharmony_ci adapter_nr)) < 0) { 14738c2ecf20Sopenharmony_ci printk("%s: dvb_register_adapter failed: error %d\n", 14748c2ecf20Sopenharmony_ci __func__, result); 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci return result; 14778c2ecf20Sopenharmony_ci } 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci dec->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci dec->demux.priv = (void *)dec; 14828c2ecf20Sopenharmony_ci dec->demux.filternum = 31; 14838c2ecf20Sopenharmony_ci dec->demux.feednum = 31; 14848c2ecf20Sopenharmony_ci dec->demux.start_feed = ttusb_dec_start_feed; 14858c2ecf20Sopenharmony_ci dec->demux.stop_feed = ttusb_dec_stop_feed; 14868c2ecf20Sopenharmony_ci dec->demux.write_to_decoder = NULL; 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci if ((result = dvb_dmx_init(&dec->demux)) < 0) { 14898c2ecf20Sopenharmony_ci printk("%s: dvb_dmx_init failed: error %d\n", __func__, 14908c2ecf20Sopenharmony_ci result); 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci dvb_unregister_adapter(&dec->adapter); 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci return result; 14958c2ecf20Sopenharmony_ci } 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci dec->dmxdev.filternum = 32; 14988c2ecf20Sopenharmony_ci dec->dmxdev.demux = &dec->demux.dmx; 14998c2ecf20Sopenharmony_ci dec->dmxdev.capabilities = 0; 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci if ((result = dvb_dmxdev_init(&dec->dmxdev, &dec->adapter)) < 0) { 15028c2ecf20Sopenharmony_ci printk("%s: dvb_dmxdev_init failed: error %d\n", 15038c2ecf20Sopenharmony_ci __func__, result); 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci dvb_dmx_release(&dec->demux); 15068c2ecf20Sopenharmony_ci dvb_unregister_adapter(&dec->adapter); 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci return result; 15098c2ecf20Sopenharmony_ci } 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci dec->frontend.source = DMX_FRONTEND_0; 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci if ((result = dec->demux.dmx.add_frontend(&dec->demux.dmx, 15148c2ecf20Sopenharmony_ci &dec->frontend)) < 0) { 15158c2ecf20Sopenharmony_ci printk("%s: dvb_dmx_init failed: error %d\n", __func__, 15168c2ecf20Sopenharmony_ci result); 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci dvb_dmxdev_release(&dec->dmxdev); 15198c2ecf20Sopenharmony_ci dvb_dmx_release(&dec->demux); 15208c2ecf20Sopenharmony_ci dvb_unregister_adapter(&dec->adapter); 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci return result; 15238c2ecf20Sopenharmony_ci } 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci if ((result = dec->demux.dmx.connect_frontend(&dec->demux.dmx, 15268c2ecf20Sopenharmony_ci &dec->frontend)) < 0) { 15278c2ecf20Sopenharmony_ci printk("%s: dvb_dmx_init failed: error %d\n", __func__, 15288c2ecf20Sopenharmony_ci result); 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend); 15318c2ecf20Sopenharmony_ci dvb_dmxdev_release(&dec->dmxdev); 15328c2ecf20Sopenharmony_ci dvb_dmx_release(&dec->demux); 15338c2ecf20Sopenharmony_ci dvb_unregister_adapter(&dec->adapter); 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci return result; 15368c2ecf20Sopenharmony_ci } 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci dvb_net_init(&dec->adapter, &dec->dvb_net, &dec->demux.dmx); 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci return 0; 15418c2ecf20Sopenharmony_ci} 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_cistatic void ttusb_dec_exit_dvb(struct ttusb_dec *dec) 15448c2ecf20Sopenharmony_ci{ 15458c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci dvb_net_release(&dec->dvb_net); 15488c2ecf20Sopenharmony_ci dec->demux.dmx.close(&dec->demux.dmx); 15498c2ecf20Sopenharmony_ci dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend); 15508c2ecf20Sopenharmony_ci dvb_dmxdev_release(&dec->dmxdev); 15518c2ecf20Sopenharmony_ci dvb_dmx_release(&dec->demux); 15528c2ecf20Sopenharmony_ci if (dec->fe) { 15538c2ecf20Sopenharmony_ci dvb_unregister_frontend(dec->fe); 15548c2ecf20Sopenharmony_ci dvb_frontend_detach(dec->fe); 15558c2ecf20Sopenharmony_ci } 15568c2ecf20Sopenharmony_ci dvb_unregister_adapter(&dec->adapter); 15578c2ecf20Sopenharmony_ci} 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_cistatic void ttusb_dec_exit_rc(struct ttusb_dec *dec) 15608c2ecf20Sopenharmony_ci{ 15618c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci if (dec->rc_input_dev) { 15648c2ecf20Sopenharmony_ci input_unregister_device(dec->rc_input_dev); 15658c2ecf20Sopenharmony_ci dec->rc_input_dev = NULL; 15668c2ecf20Sopenharmony_ci } 15678c2ecf20Sopenharmony_ci} 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_cistatic void ttusb_dec_exit_usb(struct ttusb_dec *dec) 15718c2ecf20Sopenharmony_ci{ 15728c2ecf20Sopenharmony_ci int i; 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci if (enable_rc) { 15778c2ecf20Sopenharmony_ci /* we have to check whether the irq URB is already submitted. 15788c2ecf20Sopenharmony_ci * As the irq is submitted after the interface is changed, 15798c2ecf20Sopenharmony_ci * this is the best method i figured out. 15808c2ecf20Sopenharmony_ci * Any others?*/ 15818c2ecf20Sopenharmony_ci if (dec->interface == TTUSB_DEC_INTERFACE_IN) 15828c2ecf20Sopenharmony_ci usb_kill_urb(dec->irq_urb); 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci usb_free_urb(dec->irq_urb); 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci usb_free_coherent(dec->udev, IRQ_PACKET_SIZE, 15878c2ecf20Sopenharmony_ci dec->irq_buffer, dec->irq_dma_handle); 15888c2ecf20Sopenharmony_ci } 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci dec->iso_stream_count = 0; 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci for (i = 0; i < ISO_BUF_COUNT; i++) 15938c2ecf20Sopenharmony_ci usb_kill_urb(dec->iso_urb[i]); 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci ttusb_dec_free_iso_urbs(dec); 15968c2ecf20Sopenharmony_ci} 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_cistatic void ttusb_dec_exit_tasklet(struct ttusb_dec *dec) 15998c2ecf20Sopenharmony_ci{ 16008c2ecf20Sopenharmony_ci struct list_head *item; 16018c2ecf20Sopenharmony_ci struct urb_frame *frame; 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci tasklet_kill(&dec->urb_tasklet); 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci while ((item = dec->urb_frame_list.next) != &dec->urb_frame_list) { 16068c2ecf20Sopenharmony_ci frame = list_entry(item, struct urb_frame, urb_frame_list); 16078c2ecf20Sopenharmony_ci list_del(&frame->urb_frame_list); 16088c2ecf20Sopenharmony_ci kfree(frame); 16098c2ecf20Sopenharmony_ci } 16108c2ecf20Sopenharmony_ci} 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_cistatic void ttusb_dec_init_filters(struct ttusb_dec *dec) 16138c2ecf20Sopenharmony_ci{ 16148c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dec->filter_info_list); 16158c2ecf20Sopenharmony_ci spin_lock_init(&dec->filter_info_list_lock); 16168c2ecf20Sopenharmony_ci} 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_cistatic void ttusb_dec_exit_filters(struct ttusb_dec *dec) 16198c2ecf20Sopenharmony_ci{ 16208c2ecf20Sopenharmony_ci struct list_head *item; 16218c2ecf20Sopenharmony_ci struct filter_info *finfo; 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci while ((item = dec->filter_info_list.next) != &dec->filter_info_list) { 16248c2ecf20Sopenharmony_ci finfo = list_entry(item, struct filter_info, filter_info_list); 16258c2ecf20Sopenharmony_ci list_del(&finfo->filter_info_list); 16268c2ecf20Sopenharmony_ci kfree(finfo); 16278c2ecf20Sopenharmony_ci } 16288c2ecf20Sopenharmony_ci} 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_cistatic int fe_send_command(struct dvb_frontend* fe, const u8 command, 16318c2ecf20Sopenharmony_ci int param_length, const u8 params[], 16328c2ecf20Sopenharmony_ci int *result_length, u8 cmd_result[]) 16338c2ecf20Sopenharmony_ci{ 16348c2ecf20Sopenharmony_ci struct ttusb_dec* dec = fe->dvb->priv; 16358c2ecf20Sopenharmony_ci return ttusb_dec_send_command(dec, command, param_length, params, result_length, cmd_result); 16368c2ecf20Sopenharmony_ci} 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_cistatic const struct ttusbdecfe_config fe_config = { 16398c2ecf20Sopenharmony_ci .send_command = fe_send_command 16408c2ecf20Sopenharmony_ci}; 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_cistatic int ttusb_dec_probe(struct usb_interface *intf, 16438c2ecf20Sopenharmony_ci const struct usb_device_id *id) 16448c2ecf20Sopenharmony_ci{ 16458c2ecf20Sopenharmony_ci struct usb_device *udev; 16468c2ecf20Sopenharmony_ci struct ttusb_dec *dec; 16478c2ecf20Sopenharmony_ci int result; 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_ci udev = interface_to_usbdev(intf); 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci if (!(dec = kzalloc(sizeof(struct ttusb_dec), GFP_KERNEL))) { 16548c2ecf20Sopenharmony_ci printk("%s: couldn't allocate memory.\n", __func__); 16558c2ecf20Sopenharmony_ci return -ENOMEM; 16568c2ecf20Sopenharmony_ci } 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci usb_set_intfdata(intf, (void *)dec); 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_ci switch (id->idProduct) { 16618c2ecf20Sopenharmony_ci case 0x1006: 16628c2ecf20Sopenharmony_ci ttusb_dec_set_model(dec, TTUSB_DEC3000S); 16638c2ecf20Sopenharmony_ci break; 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci case 0x1008: 16668c2ecf20Sopenharmony_ci ttusb_dec_set_model(dec, TTUSB_DEC2000T); 16678c2ecf20Sopenharmony_ci break; 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci case 0x1009: 16708c2ecf20Sopenharmony_ci ttusb_dec_set_model(dec, TTUSB_DEC2540T); 16718c2ecf20Sopenharmony_ci break; 16728c2ecf20Sopenharmony_ci } 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci dec->udev = udev; 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci result = ttusb_dec_init_usb(dec); 16778c2ecf20Sopenharmony_ci if (result) 16788c2ecf20Sopenharmony_ci goto err_usb; 16798c2ecf20Sopenharmony_ci result = ttusb_dec_init_stb(dec); 16808c2ecf20Sopenharmony_ci if (result) 16818c2ecf20Sopenharmony_ci goto err_stb; 16828c2ecf20Sopenharmony_ci result = ttusb_dec_init_dvb(dec); 16838c2ecf20Sopenharmony_ci if (result) 16848c2ecf20Sopenharmony_ci goto err_stb; 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci dec->adapter.priv = dec; 16878c2ecf20Sopenharmony_ci switch (id->idProduct) { 16888c2ecf20Sopenharmony_ci case 0x1006: 16898c2ecf20Sopenharmony_ci dec->fe = ttusbdecfe_dvbs_attach(&fe_config); 16908c2ecf20Sopenharmony_ci break; 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci case 0x1008: 16938c2ecf20Sopenharmony_ci case 0x1009: 16948c2ecf20Sopenharmony_ci dec->fe = ttusbdecfe_dvbt_attach(&fe_config); 16958c2ecf20Sopenharmony_ci break; 16968c2ecf20Sopenharmony_ci } 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci if (dec->fe == NULL) { 16998c2ecf20Sopenharmony_ci printk("dvb-ttusb-dec: A frontend driver was not found for device [%04x:%04x]\n", 17008c2ecf20Sopenharmony_ci le16_to_cpu(dec->udev->descriptor.idVendor), 17018c2ecf20Sopenharmony_ci le16_to_cpu(dec->udev->descriptor.idProduct)); 17028c2ecf20Sopenharmony_ci } else { 17038c2ecf20Sopenharmony_ci if (dvb_register_frontend(&dec->adapter, dec->fe)) { 17048c2ecf20Sopenharmony_ci printk("budget-ci: Frontend registration failed!\n"); 17058c2ecf20Sopenharmony_ci if (dec->fe->ops.release) 17068c2ecf20Sopenharmony_ci dec->fe->ops.release(dec->fe); 17078c2ecf20Sopenharmony_ci dec->fe = NULL; 17088c2ecf20Sopenharmony_ci } 17098c2ecf20Sopenharmony_ci } 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_ci ttusb_dec_init_v_pes(dec); 17128c2ecf20Sopenharmony_ci ttusb_dec_init_filters(dec); 17138c2ecf20Sopenharmony_ci ttusb_dec_init_tasklet(dec); 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci dec->active = 1; 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ci ttusb_dec_set_interface(dec, TTUSB_DEC_INTERFACE_IN); 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci if (enable_rc) 17208c2ecf20Sopenharmony_ci ttusb_init_rc(dec); 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci return 0; 17238c2ecf20Sopenharmony_cierr_stb: 17248c2ecf20Sopenharmony_ci ttusb_dec_exit_usb(dec); 17258c2ecf20Sopenharmony_cierr_usb: 17268c2ecf20Sopenharmony_ci kfree(dec); 17278c2ecf20Sopenharmony_ci return result; 17288c2ecf20Sopenharmony_ci} 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_cistatic void ttusb_dec_disconnect(struct usb_interface *intf) 17318c2ecf20Sopenharmony_ci{ 17328c2ecf20Sopenharmony_ci struct ttusb_dec *dec = usb_get_intfdata(intf); 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci usb_set_intfdata(intf, NULL); 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci if (dec->active) { 17398c2ecf20Sopenharmony_ci ttusb_dec_exit_tasklet(dec); 17408c2ecf20Sopenharmony_ci ttusb_dec_exit_filters(dec); 17418c2ecf20Sopenharmony_ci if(enable_rc) 17428c2ecf20Sopenharmony_ci ttusb_dec_exit_rc(dec); 17438c2ecf20Sopenharmony_ci ttusb_dec_exit_usb(dec); 17448c2ecf20Sopenharmony_ci ttusb_dec_exit_dvb(dec); 17458c2ecf20Sopenharmony_ci } 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_ci kfree(dec); 17488c2ecf20Sopenharmony_ci} 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_cistatic void ttusb_dec_set_model(struct ttusb_dec *dec, 17518c2ecf20Sopenharmony_ci enum ttusb_dec_model model) 17528c2ecf20Sopenharmony_ci{ 17538c2ecf20Sopenharmony_ci dec->model = model; 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci switch (model) { 17568c2ecf20Sopenharmony_ci case TTUSB_DEC2000T: 17578c2ecf20Sopenharmony_ci dec->model_name = "DEC2000-t"; 17588c2ecf20Sopenharmony_ci dec->firmware_name = "dvb-ttusb-dec-2000t.fw"; 17598c2ecf20Sopenharmony_ci break; 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci case TTUSB_DEC2540T: 17628c2ecf20Sopenharmony_ci dec->model_name = "DEC2540-t"; 17638c2ecf20Sopenharmony_ci dec->firmware_name = "dvb-ttusb-dec-2540t.fw"; 17648c2ecf20Sopenharmony_ci break; 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci case TTUSB_DEC3000S: 17678c2ecf20Sopenharmony_ci dec->model_name = "DEC3000-s"; 17688c2ecf20Sopenharmony_ci dec->firmware_name = "dvb-ttusb-dec-3000s.fw"; 17698c2ecf20Sopenharmony_ci break; 17708c2ecf20Sopenharmony_ci } 17718c2ecf20Sopenharmony_ci} 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_cistatic const struct usb_device_id ttusb_dec_table[] = { 17748c2ecf20Sopenharmony_ci {USB_DEVICE(0x0b48, 0x1006)}, /* DEC3000-s */ 17758c2ecf20Sopenharmony_ci /*{USB_DEVICE(0x0b48, 0x1007)}, Unconfirmed */ 17768c2ecf20Sopenharmony_ci {USB_DEVICE(0x0b48, 0x1008)}, /* DEC2000-t */ 17778c2ecf20Sopenharmony_ci {USB_DEVICE(0x0b48, 0x1009)}, /* DEC2540-t */ 17788c2ecf20Sopenharmony_ci {} 17798c2ecf20Sopenharmony_ci}; 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_cistatic struct usb_driver ttusb_dec_driver = { 17828c2ecf20Sopenharmony_ci .name = "ttusb-dec", 17838c2ecf20Sopenharmony_ci .probe = ttusb_dec_probe, 17848c2ecf20Sopenharmony_ci .disconnect = ttusb_dec_disconnect, 17858c2ecf20Sopenharmony_ci .id_table = ttusb_dec_table, 17868c2ecf20Sopenharmony_ci}; 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_cimodule_usb_driver(ttusb_dec_driver); 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_ciMODULE_AUTHOR("Alex Woods <linux-dvb@giblets.org>"); 17918c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_NAME); 17928c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 17938c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, ttusb_dec_table); 1794