162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * TTUSB DEC Driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2003-2004 Alex Woods <linux-dvb@giblets.org> 662306a36Sopenharmony_ci * IR support by Peter Beutner <p.beutner@gmx.net> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/list.h> 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/pci.h> 1262306a36Sopenharmony_ci#include <linux/slab.h> 1362306a36Sopenharmony_ci#include <linux/spinlock.h> 1462306a36Sopenharmony_ci#include <linux/usb.h> 1562306a36Sopenharmony_ci#include <linux/interrupt.h> 1662306a36Sopenharmony_ci#include <linux/firmware.h> 1762306a36Sopenharmony_ci#include <linux/crc32.h> 1862306a36Sopenharmony_ci#include <linux/init.h> 1962306a36Sopenharmony_ci#include <linux/input.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <linux/mutex.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include <media/dmxdev.h> 2462306a36Sopenharmony_ci#include <media/dvb_demux.h> 2562306a36Sopenharmony_ci#include <media/dvb_frontend.h> 2662306a36Sopenharmony_ci#include <media/dvb_net.h> 2762306a36Sopenharmony_ci#include "ttusbdecfe.h" 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic int debug; 3062306a36Sopenharmony_cistatic int output_pva; 3162306a36Sopenharmony_cistatic int enable_rc; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cimodule_param(debug, int, 0644); 3462306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); 3562306a36Sopenharmony_cimodule_param(output_pva, int, 0444); 3662306a36Sopenharmony_ciMODULE_PARM_DESC(output_pva, "Output PVA from dvr device (default:off)"); 3762306a36Sopenharmony_cimodule_param(enable_rc, int, 0644); 3862306a36Sopenharmony_ciMODULE_PARM_DESC(enable_rc, "Turn on/off IR remote control(default: off)"); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ciDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#define dprintk if (debug) printk 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#define DRIVER_NAME "TechnoTrend/Hauppauge DEC USB" 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#define COMMAND_PIPE 0x03 4762306a36Sopenharmony_ci#define RESULT_PIPE 0x04 4862306a36Sopenharmony_ci#define IN_PIPE 0x08 4962306a36Sopenharmony_ci#define OUT_PIPE 0x07 5062306a36Sopenharmony_ci#define IRQ_PIPE 0x0A 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define COMMAND_PACKET_SIZE 0x3c 5362306a36Sopenharmony_ci#define ARM_PACKET_SIZE 0x1000 5462306a36Sopenharmony_ci#define IRQ_PACKET_SIZE 0x8 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#define ISO_BUF_COUNT 0x04 5762306a36Sopenharmony_ci#define FRAMES_PER_ISO_BUF 0x04 5862306a36Sopenharmony_ci#define ISO_FRAME_SIZE 0x0380 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#define MAX_PVA_LENGTH 6144 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cienum ttusb_dec_model { 6362306a36Sopenharmony_ci TTUSB_DEC2000T, 6462306a36Sopenharmony_ci TTUSB_DEC2540T, 6562306a36Sopenharmony_ci TTUSB_DEC3000S 6662306a36Sopenharmony_ci}; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cienum ttusb_dec_packet_type { 6962306a36Sopenharmony_ci TTUSB_DEC_PACKET_PVA, 7062306a36Sopenharmony_ci TTUSB_DEC_PACKET_SECTION, 7162306a36Sopenharmony_ci TTUSB_DEC_PACKET_EMPTY 7262306a36Sopenharmony_ci}; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cienum ttusb_dec_interface { 7562306a36Sopenharmony_ci TTUSB_DEC_INTERFACE_INITIAL, 7662306a36Sopenharmony_ci TTUSB_DEC_INTERFACE_IN, 7762306a36Sopenharmony_ci TTUSB_DEC_INTERFACE_OUT 7862306a36Sopenharmony_ci}; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_citypedef int (dvb_filter_pes2ts_cb_t) (void *, unsigned char *); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistruct dvb_filter_pes2ts { 8362306a36Sopenharmony_ci unsigned char buf[188]; 8462306a36Sopenharmony_ci unsigned char cc; 8562306a36Sopenharmony_ci dvb_filter_pes2ts_cb_t *cb; 8662306a36Sopenharmony_ci void *priv; 8762306a36Sopenharmony_ci}; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistruct ttusb_dec { 9062306a36Sopenharmony_ci enum ttusb_dec_model model; 9162306a36Sopenharmony_ci char *model_name; 9262306a36Sopenharmony_ci char *firmware_name; 9362306a36Sopenharmony_ci int can_playback; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci /* DVB bits */ 9662306a36Sopenharmony_ci struct dvb_adapter adapter; 9762306a36Sopenharmony_ci struct dmxdev dmxdev; 9862306a36Sopenharmony_ci struct dvb_demux demux; 9962306a36Sopenharmony_ci struct dmx_frontend frontend; 10062306a36Sopenharmony_ci struct dvb_net dvb_net; 10162306a36Sopenharmony_ci struct dvb_frontend* fe; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci u16 pid[DMX_PES_OTHER]; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci /* USB bits */ 10662306a36Sopenharmony_ci struct usb_device *udev; 10762306a36Sopenharmony_ci u8 trans_count; 10862306a36Sopenharmony_ci unsigned int command_pipe; 10962306a36Sopenharmony_ci unsigned int result_pipe; 11062306a36Sopenharmony_ci unsigned int in_pipe; 11162306a36Sopenharmony_ci unsigned int out_pipe; 11262306a36Sopenharmony_ci unsigned int irq_pipe; 11362306a36Sopenharmony_ci enum ttusb_dec_interface interface; 11462306a36Sopenharmony_ci struct mutex usb_mutex; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci void *irq_buffer; 11762306a36Sopenharmony_ci struct urb *irq_urb; 11862306a36Sopenharmony_ci dma_addr_t irq_dma_handle; 11962306a36Sopenharmony_ci void *iso_buffer; 12062306a36Sopenharmony_ci struct urb *iso_urb[ISO_BUF_COUNT]; 12162306a36Sopenharmony_ci int iso_stream_count; 12262306a36Sopenharmony_ci struct mutex iso_mutex; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci u8 packet[MAX_PVA_LENGTH + 4]; 12562306a36Sopenharmony_ci enum ttusb_dec_packet_type packet_type; 12662306a36Sopenharmony_ci int packet_state; 12762306a36Sopenharmony_ci int packet_length; 12862306a36Sopenharmony_ci int packet_payload_length; 12962306a36Sopenharmony_ci u16 next_packet_id; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci int pva_stream_count; 13262306a36Sopenharmony_ci int filter_stream_count; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci struct dvb_filter_pes2ts a_pes2ts; 13562306a36Sopenharmony_ci struct dvb_filter_pes2ts v_pes2ts; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci u8 v_pes[16 + MAX_PVA_LENGTH]; 13862306a36Sopenharmony_ci int v_pes_length; 13962306a36Sopenharmony_ci int v_pes_postbytes; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci struct list_head urb_frame_list; 14262306a36Sopenharmony_ci struct tasklet_struct urb_tasklet; 14362306a36Sopenharmony_ci spinlock_t urb_frame_list_lock; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci struct dvb_demux_filter *audio_filter; 14662306a36Sopenharmony_ci struct dvb_demux_filter *video_filter; 14762306a36Sopenharmony_ci struct list_head filter_info_list; 14862306a36Sopenharmony_ci spinlock_t filter_info_list_lock; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci struct input_dev *rc_input_dev; 15162306a36Sopenharmony_ci char rc_phys[64]; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci int active; /* Loaded successfully */ 15462306a36Sopenharmony_ci}; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistruct urb_frame { 15762306a36Sopenharmony_ci u8 data[ISO_FRAME_SIZE]; 15862306a36Sopenharmony_ci int length; 15962306a36Sopenharmony_ci struct list_head urb_frame_list; 16062306a36Sopenharmony_ci}; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistruct filter_info { 16362306a36Sopenharmony_ci u8 stream_id; 16462306a36Sopenharmony_ci struct dvb_demux_filter *filter; 16562306a36Sopenharmony_ci struct list_head filter_info_list; 16662306a36Sopenharmony_ci}; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic u16 rc_keys[] = { 16962306a36Sopenharmony_ci KEY_POWER, 17062306a36Sopenharmony_ci KEY_MUTE, 17162306a36Sopenharmony_ci KEY_1, 17262306a36Sopenharmony_ci KEY_2, 17362306a36Sopenharmony_ci KEY_3, 17462306a36Sopenharmony_ci KEY_4, 17562306a36Sopenharmony_ci KEY_5, 17662306a36Sopenharmony_ci KEY_6, 17762306a36Sopenharmony_ci KEY_7, 17862306a36Sopenharmony_ci KEY_8, 17962306a36Sopenharmony_ci KEY_9, 18062306a36Sopenharmony_ci KEY_0, 18162306a36Sopenharmony_ci KEY_CHANNELUP, 18262306a36Sopenharmony_ci KEY_VOLUMEDOWN, 18362306a36Sopenharmony_ci KEY_OK, 18462306a36Sopenharmony_ci KEY_VOLUMEUP, 18562306a36Sopenharmony_ci KEY_CHANNELDOWN, 18662306a36Sopenharmony_ci KEY_PREVIOUS, 18762306a36Sopenharmony_ci KEY_ESC, 18862306a36Sopenharmony_ci KEY_RED, 18962306a36Sopenharmony_ci KEY_GREEN, 19062306a36Sopenharmony_ci KEY_YELLOW, 19162306a36Sopenharmony_ci KEY_BLUE, 19262306a36Sopenharmony_ci KEY_OPTION, 19362306a36Sopenharmony_ci KEY_M, 19462306a36Sopenharmony_ci KEY_RADIO 19562306a36Sopenharmony_ci}; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, 19862306a36Sopenharmony_ci unsigned short pid, 19962306a36Sopenharmony_ci dvb_filter_pes2ts_cb_t *cb, void *priv) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci unsigned char *buf=p2ts->buf; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci buf[0]=0x47; 20462306a36Sopenharmony_ci buf[1]=(pid>>8); 20562306a36Sopenharmony_ci buf[2]=pid&0xff; 20662306a36Sopenharmony_ci p2ts->cc=0; 20762306a36Sopenharmony_ci p2ts->cb=cb; 20862306a36Sopenharmony_ci p2ts->priv=priv; 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, 21262306a36Sopenharmony_ci unsigned char *pes, int len, int payload_start) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci unsigned char *buf=p2ts->buf; 21562306a36Sopenharmony_ci int ret=0, rest; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci //len=6+((pes[4]<<8)|pes[5]); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci if (payload_start) 22062306a36Sopenharmony_ci buf[1]|=0x40; 22162306a36Sopenharmony_ci else 22262306a36Sopenharmony_ci buf[1]&=~0x40; 22362306a36Sopenharmony_ci while (len>=184) { 22462306a36Sopenharmony_ci buf[3]=0x10|((p2ts->cc++)&0x0f); 22562306a36Sopenharmony_ci memcpy(buf+4, pes, 184); 22662306a36Sopenharmony_ci if ((ret=p2ts->cb(p2ts->priv, buf))) 22762306a36Sopenharmony_ci return ret; 22862306a36Sopenharmony_ci len-=184; pes+=184; 22962306a36Sopenharmony_ci buf[1]&=~0x40; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci if (!len) 23262306a36Sopenharmony_ci return 0; 23362306a36Sopenharmony_ci buf[3]=0x30|((p2ts->cc++)&0x0f); 23462306a36Sopenharmony_ci rest=183-len; 23562306a36Sopenharmony_ci if (rest) { 23662306a36Sopenharmony_ci buf[5]=0x00; 23762306a36Sopenharmony_ci if (rest-1) 23862306a36Sopenharmony_ci memset(buf+6, 0xff, rest-1); 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci buf[4]=rest; 24162306a36Sopenharmony_ci memcpy(buf+5+rest, pes, len); 24262306a36Sopenharmony_ci return p2ts->cb(p2ts->priv, buf); 24362306a36Sopenharmony_ci} 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_cistatic void ttusb_dec_set_model(struct ttusb_dec *dec, 24662306a36Sopenharmony_ci enum ttusb_dec_model model); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic void ttusb_dec_handle_irq( struct urb *urb) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci struct ttusb_dec *dec = urb->context; 25162306a36Sopenharmony_ci char *buffer = dec->irq_buffer; 25262306a36Sopenharmony_ci int retval; 25362306a36Sopenharmony_ci int index = buffer[4]; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci switch(urb->status) { 25662306a36Sopenharmony_ci case 0: /*success*/ 25762306a36Sopenharmony_ci break; 25862306a36Sopenharmony_ci case -ECONNRESET: 25962306a36Sopenharmony_ci case -ENOENT: 26062306a36Sopenharmony_ci case -ESHUTDOWN: 26162306a36Sopenharmony_ci case -ETIME: 26262306a36Sopenharmony_ci /* this urb is dead, cleanup */ 26362306a36Sopenharmony_ci dprintk("%s:urb shutting down with status: %d\n", 26462306a36Sopenharmony_ci __func__, urb->status); 26562306a36Sopenharmony_ci return; 26662306a36Sopenharmony_ci default: 26762306a36Sopenharmony_ci dprintk("%s:nonzero status received: %d\n", 26862306a36Sopenharmony_ci __func__,urb->status); 26962306a36Sopenharmony_ci goto exit; 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci if ((buffer[0] == 0x1) && (buffer[2] == 0x15)) { 27362306a36Sopenharmony_ci /* 27462306a36Sopenharmony_ci * IR - Event 27562306a36Sopenharmony_ci * 27662306a36Sopenharmony_ci * this is an fact a bit too simple implementation; 27762306a36Sopenharmony_ci * the box also reports a keyrepeat signal 27862306a36Sopenharmony_ci * (with buffer[3] == 0x40) in an interval of ~100ms. 27962306a36Sopenharmony_ci * But to handle this correctly we had to imlemenent some 28062306a36Sopenharmony_ci * kind of timer which signals a 'key up' event if no 28162306a36Sopenharmony_ci * keyrepeat signal is received for lets say 200ms. 28262306a36Sopenharmony_ci * this should/could be added later ... 28362306a36Sopenharmony_ci * for now lets report each signal as a key down and up 28462306a36Sopenharmony_ci */ 28562306a36Sopenharmony_ci if (index - 1 < ARRAY_SIZE(rc_keys)) { 28662306a36Sopenharmony_ci dprintk("%s:rc signal:%d\n", __func__, index); 28762306a36Sopenharmony_ci input_report_key(dec->rc_input_dev, rc_keys[index - 1], 1); 28862306a36Sopenharmony_ci input_sync(dec->rc_input_dev); 28962306a36Sopenharmony_ci input_report_key(dec->rc_input_dev, rc_keys[index - 1], 0); 29062306a36Sopenharmony_ci input_sync(dec->rc_input_dev); 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ciexit: 29562306a36Sopenharmony_ci retval = usb_submit_urb(urb, GFP_ATOMIC); 29662306a36Sopenharmony_ci if (retval) 29762306a36Sopenharmony_ci printk("%s - usb_commit_urb failed with result: %d\n", 29862306a36Sopenharmony_ci __func__, retval); 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_cistatic u16 crc16(u16 crc, const u8 *buf, size_t len) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci u16 tmp; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci while (len--) { 30662306a36Sopenharmony_ci crc ^= *buf++; 30762306a36Sopenharmony_ci crc ^= (u8)crc >> 4; 30862306a36Sopenharmony_ci tmp = (u8)crc; 30962306a36Sopenharmony_ci crc ^= (tmp ^ (tmp << 1)) << 4; 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci return crc; 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cistatic int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command, 31562306a36Sopenharmony_ci int param_length, const u8 params[], 31662306a36Sopenharmony_ci int *result_length, u8 cmd_result[]) 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci int result, actual_len; 31962306a36Sopenharmony_ci u8 *b; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci dprintk("%s\n", __func__); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci b = kzalloc(COMMAND_PACKET_SIZE + 4, GFP_KERNEL); 32462306a36Sopenharmony_ci if (!b) 32562306a36Sopenharmony_ci return -ENOMEM; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci result = mutex_lock_interruptible(&dec->usb_mutex); 32862306a36Sopenharmony_ci if (result) { 32962306a36Sopenharmony_ci printk("%s: Failed to lock usb mutex.\n", __func__); 33062306a36Sopenharmony_ci goto err_free; 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci b[0] = 0xaa; 33462306a36Sopenharmony_ci b[1] = ++dec->trans_count; 33562306a36Sopenharmony_ci b[2] = command; 33662306a36Sopenharmony_ci b[3] = param_length; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci if (params) 33962306a36Sopenharmony_ci memcpy(&b[4], params, param_length); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci if (debug) { 34262306a36Sopenharmony_ci printk(KERN_DEBUG "%s: command: %*ph\n", 34362306a36Sopenharmony_ci __func__, param_length, b); 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci result = usb_bulk_msg(dec->udev, dec->command_pipe, b, 34762306a36Sopenharmony_ci COMMAND_PACKET_SIZE + 4, &actual_len, 1000); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci if (result) { 35062306a36Sopenharmony_ci printk("%s: command bulk message failed: error %d\n", 35162306a36Sopenharmony_ci __func__, result); 35262306a36Sopenharmony_ci goto err_mutex_unlock; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci result = usb_bulk_msg(dec->udev, dec->result_pipe, b, 35662306a36Sopenharmony_ci COMMAND_PACKET_SIZE + 4, &actual_len, 1000); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (result) { 35962306a36Sopenharmony_ci printk("%s: result bulk message failed: error %d\n", 36062306a36Sopenharmony_ci __func__, result); 36162306a36Sopenharmony_ci goto err_mutex_unlock; 36262306a36Sopenharmony_ci } else { 36362306a36Sopenharmony_ci if (debug) { 36462306a36Sopenharmony_ci printk(KERN_DEBUG "%s: result: %*ph\n", 36562306a36Sopenharmony_ci __func__, actual_len, b); 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci if (result_length) 36962306a36Sopenharmony_ci *result_length = b[3]; 37062306a36Sopenharmony_ci if (cmd_result && b[3] > 0) 37162306a36Sopenharmony_ci memcpy(cmd_result, &b[4], b[3]); 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cierr_mutex_unlock: 37562306a36Sopenharmony_ci mutex_unlock(&dec->usb_mutex); 37662306a36Sopenharmony_cierr_free: 37762306a36Sopenharmony_ci kfree(b); 37862306a36Sopenharmony_ci return result; 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_cistatic int ttusb_dec_get_stb_state (struct ttusb_dec *dec, unsigned int *mode, 38262306a36Sopenharmony_ci unsigned int *model, unsigned int *version) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci u8 c[COMMAND_PACKET_SIZE]; 38562306a36Sopenharmony_ci int c_length; 38662306a36Sopenharmony_ci int result; 38762306a36Sopenharmony_ci __be32 tmp; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci dprintk("%s\n", __func__); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci result = ttusb_dec_send_command(dec, 0x08, 0, NULL, &c_length, c); 39262306a36Sopenharmony_ci if (result) 39362306a36Sopenharmony_ci return result; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (c_length >= 0x0c) { 39662306a36Sopenharmony_ci if (mode != NULL) { 39762306a36Sopenharmony_ci memcpy(&tmp, c, 4); 39862306a36Sopenharmony_ci *mode = ntohl(tmp); 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci if (model != NULL) { 40162306a36Sopenharmony_ci memcpy(&tmp, &c[4], 4); 40262306a36Sopenharmony_ci *model = ntohl(tmp); 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci if (version != NULL) { 40562306a36Sopenharmony_ci memcpy(&tmp, &c[8], 4); 40662306a36Sopenharmony_ci *version = ntohl(tmp); 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci return 0; 40962306a36Sopenharmony_ci } else { 41062306a36Sopenharmony_ci return -ENOENT; 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci} 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_cistatic int ttusb_dec_audio_pes2ts_cb(void *priv, unsigned char *data) 41562306a36Sopenharmony_ci{ 41662306a36Sopenharmony_ci struct ttusb_dec *dec = priv; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci dec->audio_filter->feed->cb.ts(data, 188, NULL, 0, 41962306a36Sopenharmony_ci &dec->audio_filter->feed->feed.ts, NULL); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci return 0; 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_cistatic int ttusb_dec_video_pes2ts_cb(void *priv, unsigned char *data) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci struct ttusb_dec *dec = priv; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci dec->video_filter->feed->cb.ts(data, 188, NULL, 0, 42962306a36Sopenharmony_ci &dec->video_filter->feed->feed.ts, NULL); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci return 0; 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_cistatic void ttusb_dec_set_pids(struct ttusb_dec *dec) 43562306a36Sopenharmony_ci{ 43662306a36Sopenharmony_ci u8 b[] = { 0x00, 0x00, 0x00, 0x00, 43762306a36Sopenharmony_ci 0x00, 0x00, 0xff, 0xff, 43862306a36Sopenharmony_ci 0xff, 0xff, 0xff, 0xff }; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci __be16 pcr = htons(dec->pid[DMX_PES_PCR]); 44162306a36Sopenharmony_ci __be16 audio = htons(dec->pid[DMX_PES_AUDIO]); 44262306a36Sopenharmony_ci __be16 video = htons(dec->pid[DMX_PES_VIDEO]); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci dprintk("%s\n", __func__); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci memcpy(&b[0], &pcr, 2); 44762306a36Sopenharmony_ci memcpy(&b[2], &audio, 2); 44862306a36Sopenharmony_ci memcpy(&b[4], &video, 2); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci ttusb_dec_send_command(dec, 0x50, sizeof(b), b, NULL, NULL); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci dvb_filter_pes2ts_init(&dec->a_pes2ts, dec->pid[DMX_PES_AUDIO], 45362306a36Sopenharmony_ci ttusb_dec_audio_pes2ts_cb, dec); 45462306a36Sopenharmony_ci dvb_filter_pes2ts_init(&dec->v_pes2ts, dec->pid[DMX_PES_VIDEO], 45562306a36Sopenharmony_ci ttusb_dec_video_pes2ts_cb, dec); 45662306a36Sopenharmony_ci dec->v_pes_length = 0; 45762306a36Sopenharmony_ci dec->v_pes_postbytes = 0; 45862306a36Sopenharmony_ci} 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_cistatic void ttusb_dec_process_pva(struct ttusb_dec *dec, u8 *pva, int length) 46162306a36Sopenharmony_ci{ 46262306a36Sopenharmony_ci if (length < 8) { 46362306a36Sopenharmony_ci printk("%s: packet too short - discarding\n", __func__); 46462306a36Sopenharmony_ci return; 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci if (length > 8 + MAX_PVA_LENGTH) { 46862306a36Sopenharmony_ci printk("%s: packet too long - discarding\n", __func__); 46962306a36Sopenharmony_ci return; 47062306a36Sopenharmony_ci } 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci switch (pva[2]) { 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci case 0x01: { /* VideoStream */ 47562306a36Sopenharmony_ci int prebytes = pva[5] & 0x03; 47662306a36Sopenharmony_ci int postbytes = (pva[5] & 0x0c) >> 2; 47762306a36Sopenharmony_ci __be16 v_pes_payload_length; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci if (output_pva) { 48062306a36Sopenharmony_ci dec->video_filter->feed->cb.ts(pva, length, NULL, 0, 48162306a36Sopenharmony_ci &dec->video_filter->feed->feed.ts, NULL); 48262306a36Sopenharmony_ci return; 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci if (dec->v_pes_postbytes > 0 && 48662306a36Sopenharmony_ci dec->v_pes_postbytes == prebytes) { 48762306a36Sopenharmony_ci memcpy(&dec->v_pes[dec->v_pes_length], 48862306a36Sopenharmony_ci &pva[12], prebytes); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes, 49162306a36Sopenharmony_ci dec->v_pes_length + prebytes, 1); 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci if (pva[5] & 0x10) { 49562306a36Sopenharmony_ci dec->v_pes[7] = 0x80; 49662306a36Sopenharmony_ci dec->v_pes[8] = 0x05; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci dec->v_pes[9] = 0x21 | ((pva[8] & 0xc0) >> 5); 49962306a36Sopenharmony_ci dec->v_pes[10] = ((pva[8] & 0x3f) << 2) | 50062306a36Sopenharmony_ci ((pva[9] & 0xc0) >> 6); 50162306a36Sopenharmony_ci dec->v_pes[11] = 0x01 | 50262306a36Sopenharmony_ci ((pva[9] & 0x3f) << 2) | 50362306a36Sopenharmony_ci ((pva[10] & 0x80) >> 6); 50462306a36Sopenharmony_ci dec->v_pes[12] = ((pva[10] & 0x7f) << 1) | 50562306a36Sopenharmony_ci ((pva[11] & 0xc0) >> 7); 50662306a36Sopenharmony_ci dec->v_pes[13] = 0x01 | ((pva[11] & 0x7f) << 1); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci memcpy(&dec->v_pes[14], &pva[12 + prebytes], 50962306a36Sopenharmony_ci length - 12 - prebytes); 51062306a36Sopenharmony_ci dec->v_pes_length = 14 + length - 12 - prebytes; 51162306a36Sopenharmony_ci } else { 51262306a36Sopenharmony_ci dec->v_pes[7] = 0x00; 51362306a36Sopenharmony_ci dec->v_pes[8] = 0x00; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci memcpy(&dec->v_pes[9], &pva[8], length - 8); 51662306a36Sopenharmony_ci dec->v_pes_length = 9 + length - 8; 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci dec->v_pes_postbytes = postbytes; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci if (dec->v_pes[9 + dec->v_pes[8]] == 0x00 && 52262306a36Sopenharmony_ci dec->v_pes[10 + dec->v_pes[8]] == 0x00 && 52362306a36Sopenharmony_ci dec->v_pes[11 + dec->v_pes[8]] == 0x01) 52462306a36Sopenharmony_ci dec->v_pes[6] = 0x84; 52562306a36Sopenharmony_ci else 52662306a36Sopenharmony_ci dec->v_pes[6] = 0x80; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci v_pes_payload_length = htons(dec->v_pes_length - 6 + 52962306a36Sopenharmony_ci postbytes); 53062306a36Sopenharmony_ci memcpy(&dec->v_pes[4], &v_pes_payload_length, 2); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci if (postbytes == 0) 53362306a36Sopenharmony_ci dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes, 53462306a36Sopenharmony_ci dec->v_pes_length, 1); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci break; 53762306a36Sopenharmony_ci } 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci case 0x02: /* MainAudioStream */ 54062306a36Sopenharmony_ci if (output_pva) { 54162306a36Sopenharmony_ci dec->audio_filter->feed->cb.ts(pva, length, NULL, 0, 54262306a36Sopenharmony_ci &dec->audio_filter->feed->feed.ts, NULL); 54362306a36Sopenharmony_ci return; 54462306a36Sopenharmony_ci } 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci dvb_filter_pes2ts(&dec->a_pes2ts, &pva[8], length - 8, 54762306a36Sopenharmony_ci pva[5] & 0x10); 54862306a36Sopenharmony_ci break; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci default: 55162306a36Sopenharmony_ci printk("%s: unknown PVA type: %02x.\n", __func__, 55262306a36Sopenharmony_ci pva[2]); 55362306a36Sopenharmony_ci break; 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci} 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_cistatic void ttusb_dec_process_filter(struct ttusb_dec *dec, u8 *packet, 55862306a36Sopenharmony_ci int length) 55962306a36Sopenharmony_ci{ 56062306a36Sopenharmony_ci struct list_head *item; 56162306a36Sopenharmony_ci struct filter_info *finfo; 56262306a36Sopenharmony_ci struct dvb_demux_filter *filter = NULL; 56362306a36Sopenharmony_ci unsigned long flags; 56462306a36Sopenharmony_ci u8 sid; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci sid = packet[1]; 56762306a36Sopenharmony_ci spin_lock_irqsave(&dec->filter_info_list_lock, flags); 56862306a36Sopenharmony_ci for (item = dec->filter_info_list.next; item != &dec->filter_info_list; 56962306a36Sopenharmony_ci item = item->next) { 57062306a36Sopenharmony_ci finfo = list_entry(item, struct filter_info, filter_info_list); 57162306a36Sopenharmony_ci if (finfo->stream_id == sid) { 57262306a36Sopenharmony_ci filter = finfo->filter; 57362306a36Sopenharmony_ci break; 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci } 57662306a36Sopenharmony_ci spin_unlock_irqrestore(&dec->filter_info_list_lock, flags); 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci if (filter) 57962306a36Sopenharmony_ci filter->feed->cb.sec(&packet[2], length - 2, NULL, 0, 58062306a36Sopenharmony_ci &filter->filter, NULL); 58162306a36Sopenharmony_ci} 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_cistatic void ttusb_dec_process_packet(struct ttusb_dec *dec) 58462306a36Sopenharmony_ci{ 58562306a36Sopenharmony_ci int i; 58662306a36Sopenharmony_ci u16 csum = 0; 58762306a36Sopenharmony_ci u16 packet_id; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci if (dec->packet_length % 2) { 59062306a36Sopenharmony_ci printk("%s: odd sized packet - discarding\n", __func__); 59162306a36Sopenharmony_ci return; 59262306a36Sopenharmony_ci } 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci for (i = 0; i < dec->packet_length; i += 2) 59562306a36Sopenharmony_ci csum ^= ((dec->packet[i] << 8) + dec->packet[i + 1]); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci if (csum) { 59862306a36Sopenharmony_ci printk("%s: checksum failed - discarding\n", __func__); 59962306a36Sopenharmony_ci return; 60062306a36Sopenharmony_ci } 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci packet_id = dec->packet[dec->packet_length - 4] << 8; 60362306a36Sopenharmony_ci packet_id += dec->packet[dec->packet_length - 3]; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci if ((packet_id != dec->next_packet_id) && dec->next_packet_id) { 60662306a36Sopenharmony_ci printk("%s: warning: lost packets between %u and %u\n", 60762306a36Sopenharmony_ci __func__, dec->next_packet_id - 1, packet_id); 60862306a36Sopenharmony_ci } 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci if (packet_id == 0xffff) 61162306a36Sopenharmony_ci dec->next_packet_id = 0x8000; 61262306a36Sopenharmony_ci else 61362306a36Sopenharmony_ci dec->next_packet_id = packet_id + 1; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci switch (dec->packet_type) { 61662306a36Sopenharmony_ci case TTUSB_DEC_PACKET_PVA: 61762306a36Sopenharmony_ci if (dec->pva_stream_count) 61862306a36Sopenharmony_ci ttusb_dec_process_pva(dec, dec->packet, 61962306a36Sopenharmony_ci dec->packet_payload_length); 62062306a36Sopenharmony_ci break; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci case TTUSB_DEC_PACKET_SECTION: 62362306a36Sopenharmony_ci if (dec->filter_stream_count) 62462306a36Sopenharmony_ci ttusb_dec_process_filter(dec, dec->packet, 62562306a36Sopenharmony_ci dec->packet_payload_length); 62662306a36Sopenharmony_ci break; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci case TTUSB_DEC_PACKET_EMPTY: 62962306a36Sopenharmony_ci break; 63062306a36Sopenharmony_ci } 63162306a36Sopenharmony_ci} 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_cistatic void swap_bytes(u8 *b, int length) 63462306a36Sopenharmony_ci{ 63562306a36Sopenharmony_ci length -= length % 2; 63662306a36Sopenharmony_ci for (; length; b += 2, length -= 2) 63762306a36Sopenharmony_ci swap(*b, *(b + 1)); 63862306a36Sopenharmony_ci} 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_cistatic void ttusb_dec_process_urb_frame(struct ttusb_dec *dec, u8 *b, 64162306a36Sopenharmony_ci int length) 64262306a36Sopenharmony_ci{ 64362306a36Sopenharmony_ci swap_bytes(b, length); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci while (length) { 64662306a36Sopenharmony_ci switch (dec->packet_state) { 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci case 0: 64962306a36Sopenharmony_ci case 1: 65062306a36Sopenharmony_ci case 2: 65162306a36Sopenharmony_ci if (*b++ == 0xaa) 65262306a36Sopenharmony_ci dec->packet_state++; 65362306a36Sopenharmony_ci else 65462306a36Sopenharmony_ci dec->packet_state = 0; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci length--; 65762306a36Sopenharmony_ci break; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci case 3: 66062306a36Sopenharmony_ci if (*b == 0x00) { 66162306a36Sopenharmony_ci dec->packet_state++; 66262306a36Sopenharmony_ci dec->packet_length = 0; 66362306a36Sopenharmony_ci } else if (*b != 0xaa) { 66462306a36Sopenharmony_ci dec->packet_state = 0; 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci b++; 66862306a36Sopenharmony_ci length--; 66962306a36Sopenharmony_ci break; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci case 4: 67262306a36Sopenharmony_ci dec->packet[dec->packet_length++] = *b++; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci if (dec->packet_length == 2) { 67562306a36Sopenharmony_ci if (dec->packet[0] == 'A' && 67662306a36Sopenharmony_ci dec->packet[1] == 'V') { 67762306a36Sopenharmony_ci dec->packet_type = 67862306a36Sopenharmony_ci TTUSB_DEC_PACKET_PVA; 67962306a36Sopenharmony_ci dec->packet_state++; 68062306a36Sopenharmony_ci } else if (dec->packet[0] == 'S') { 68162306a36Sopenharmony_ci dec->packet_type = 68262306a36Sopenharmony_ci TTUSB_DEC_PACKET_SECTION; 68362306a36Sopenharmony_ci dec->packet_state++; 68462306a36Sopenharmony_ci } else if (dec->packet[0] == 0x00) { 68562306a36Sopenharmony_ci dec->packet_type = 68662306a36Sopenharmony_ci TTUSB_DEC_PACKET_EMPTY; 68762306a36Sopenharmony_ci dec->packet_payload_length = 2; 68862306a36Sopenharmony_ci dec->packet_state = 7; 68962306a36Sopenharmony_ci } else { 69062306a36Sopenharmony_ci printk("%s: unknown packet type: %02x%02x\n", 69162306a36Sopenharmony_ci __func__, 69262306a36Sopenharmony_ci dec->packet[0], dec->packet[1]); 69362306a36Sopenharmony_ci dec->packet_state = 0; 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci length--; 69862306a36Sopenharmony_ci break; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci case 5: 70162306a36Sopenharmony_ci dec->packet[dec->packet_length++] = *b++; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci if (dec->packet_type == TTUSB_DEC_PACKET_PVA && 70462306a36Sopenharmony_ci dec->packet_length == 8) { 70562306a36Sopenharmony_ci dec->packet_state++; 70662306a36Sopenharmony_ci dec->packet_payload_length = 8 + 70762306a36Sopenharmony_ci (dec->packet[6] << 8) + 70862306a36Sopenharmony_ci dec->packet[7]; 70962306a36Sopenharmony_ci } else if (dec->packet_type == 71062306a36Sopenharmony_ci TTUSB_DEC_PACKET_SECTION && 71162306a36Sopenharmony_ci dec->packet_length == 5) { 71262306a36Sopenharmony_ci dec->packet_state++; 71362306a36Sopenharmony_ci dec->packet_payload_length = 5 + 71462306a36Sopenharmony_ci ((dec->packet[3] & 0x0f) << 8) + 71562306a36Sopenharmony_ci dec->packet[4]; 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci length--; 71962306a36Sopenharmony_ci break; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci case 6: { 72262306a36Sopenharmony_ci int remainder = dec->packet_payload_length - 72362306a36Sopenharmony_ci dec->packet_length; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci if (length >= remainder) { 72662306a36Sopenharmony_ci memcpy(dec->packet + dec->packet_length, 72762306a36Sopenharmony_ci b, remainder); 72862306a36Sopenharmony_ci dec->packet_length += remainder; 72962306a36Sopenharmony_ci b += remainder; 73062306a36Sopenharmony_ci length -= remainder; 73162306a36Sopenharmony_ci dec->packet_state++; 73262306a36Sopenharmony_ci } else { 73362306a36Sopenharmony_ci memcpy(&dec->packet[dec->packet_length], 73462306a36Sopenharmony_ci b, length); 73562306a36Sopenharmony_ci dec->packet_length += length; 73662306a36Sopenharmony_ci length = 0; 73762306a36Sopenharmony_ci } 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci break; 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci case 7: { 74362306a36Sopenharmony_ci int tail = 4; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci dec->packet[dec->packet_length++] = *b++; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci if (dec->packet_type == TTUSB_DEC_PACKET_SECTION && 74862306a36Sopenharmony_ci dec->packet_payload_length % 2) 74962306a36Sopenharmony_ci tail++; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci if (dec->packet_length == 75262306a36Sopenharmony_ci dec->packet_payload_length + tail) { 75362306a36Sopenharmony_ci ttusb_dec_process_packet(dec); 75462306a36Sopenharmony_ci dec->packet_state = 0; 75562306a36Sopenharmony_ci } 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci length--; 75862306a36Sopenharmony_ci break; 75962306a36Sopenharmony_ci } 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci default: 76262306a36Sopenharmony_ci printk("%s: illegal packet state encountered.\n", 76362306a36Sopenharmony_ci __func__); 76462306a36Sopenharmony_ci dec->packet_state = 0; 76562306a36Sopenharmony_ci } 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci} 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_cistatic void ttusb_dec_process_urb_frame_list(struct tasklet_struct *t) 77062306a36Sopenharmony_ci{ 77162306a36Sopenharmony_ci struct ttusb_dec *dec = from_tasklet(dec, t, urb_tasklet); 77262306a36Sopenharmony_ci struct list_head *item; 77362306a36Sopenharmony_ci struct urb_frame *frame; 77462306a36Sopenharmony_ci unsigned long flags; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci while (1) { 77762306a36Sopenharmony_ci spin_lock_irqsave(&dec->urb_frame_list_lock, flags); 77862306a36Sopenharmony_ci if ((item = dec->urb_frame_list.next) != &dec->urb_frame_list) { 77962306a36Sopenharmony_ci frame = list_entry(item, struct urb_frame, 78062306a36Sopenharmony_ci urb_frame_list); 78162306a36Sopenharmony_ci list_del(&frame->urb_frame_list); 78262306a36Sopenharmony_ci } else { 78362306a36Sopenharmony_ci spin_unlock_irqrestore(&dec->urb_frame_list_lock, 78462306a36Sopenharmony_ci flags); 78562306a36Sopenharmony_ci return; 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci spin_unlock_irqrestore(&dec->urb_frame_list_lock, flags); 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci ttusb_dec_process_urb_frame(dec, frame->data, frame->length); 79062306a36Sopenharmony_ci kfree(frame); 79162306a36Sopenharmony_ci } 79262306a36Sopenharmony_ci} 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_cistatic void ttusb_dec_process_urb(struct urb *urb) 79562306a36Sopenharmony_ci{ 79662306a36Sopenharmony_ci struct ttusb_dec *dec = urb->context; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci if (!urb->status) { 79962306a36Sopenharmony_ci int i; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci for (i = 0; i < FRAMES_PER_ISO_BUF; i++) { 80262306a36Sopenharmony_ci struct usb_iso_packet_descriptor *d; 80362306a36Sopenharmony_ci u8 *b; 80462306a36Sopenharmony_ci int length; 80562306a36Sopenharmony_ci struct urb_frame *frame; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci d = &urb->iso_frame_desc[i]; 80862306a36Sopenharmony_ci b = urb->transfer_buffer + d->offset; 80962306a36Sopenharmony_ci length = d->actual_length; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci if ((frame = kmalloc(sizeof(struct urb_frame), 81262306a36Sopenharmony_ci GFP_ATOMIC))) { 81362306a36Sopenharmony_ci unsigned long flags; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci memcpy(frame->data, b, length); 81662306a36Sopenharmony_ci frame->length = length; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci spin_lock_irqsave(&dec->urb_frame_list_lock, 81962306a36Sopenharmony_ci flags); 82062306a36Sopenharmony_ci list_add_tail(&frame->urb_frame_list, 82162306a36Sopenharmony_ci &dec->urb_frame_list); 82262306a36Sopenharmony_ci spin_unlock_irqrestore(&dec->urb_frame_list_lock, 82362306a36Sopenharmony_ci flags); 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci tasklet_schedule(&dec->urb_tasklet); 82662306a36Sopenharmony_ci } 82762306a36Sopenharmony_ci } 82862306a36Sopenharmony_ci } else { 82962306a36Sopenharmony_ci /* -ENOENT is expected when unlinking urbs */ 83062306a36Sopenharmony_ci if (urb->status != -ENOENT) 83162306a36Sopenharmony_ci dprintk("%s: urb error: %d\n", __func__, 83262306a36Sopenharmony_ci urb->status); 83362306a36Sopenharmony_ci } 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci if (dec->iso_stream_count) 83662306a36Sopenharmony_ci usb_submit_urb(urb, GFP_ATOMIC); 83762306a36Sopenharmony_ci} 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_cistatic void ttusb_dec_setup_urbs(struct ttusb_dec *dec) 84062306a36Sopenharmony_ci{ 84162306a36Sopenharmony_ci int i, j, buffer_offset = 0; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci dprintk("%s\n", __func__); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci for (i = 0; i < ISO_BUF_COUNT; i++) { 84662306a36Sopenharmony_ci int frame_offset = 0; 84762306a36Sopenharmony_ci struct urb *urb = dec->iso_urb[i]; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci urb->dev = dec->udev; 85062306a36Sopenharmony_ci urb->context = dec; 85162306a36Sopenharmony_ci urb->complete = ttusb_dec_process_urb; 85262306a36Sopenharmony_ci urb->pipe = dec->in_pipe; 85362306a36Sopenharmony_ci urb->transfer_flags = URB_ISO_ASAP; 85462306a36Sopenharmony_ci urb->interval = 1; 85562306a36Sopenharmony_ci urb->number_of_packets = FRAMES_PER_ISO_BUF; 85662306a36Sopenharmony_ci urb->transfer_buffer_length = ISO_FRAME_SIZE * 85762306a36Sopenharmony_ci FRAMES_PER_ISO_BUF; 85862306a36Sopenharmony_ci urb->transfer_buffer = dec->iso_buffer + buffer_offset; 85962306a36Sopenharmony_ci buffer_offset += ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF; 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci for (j = 0; j < FRAMES_PER_ISO_BUF; j++) { 86262306a36Sopenharmony_ci urb->iso_frame_desc[j].offset = frame_offset; 86362306a36Sopenharmony_ci urb->iso_frame_desc[j].length = ISO_FRAME_SIZE; 86462306a36Sopenharmony_ci frame_offset += ISO_FRAME_SIZE; 86562306a36Sopenharmony_ci } 86662306a36Sopenharmony_ci } 86762306a36Sopenharmony_ci} 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_cistatic void ttusb_dec_stop_iso_xfer(struct ttusb_dec *dec) 87062306a36Sopenharmony_ci{ 87162306a36Sopenharmony_ci int i; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci dprintk("%s\n", __func__); 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci if (mutex_lock_interruptible(&dec->iso_mutex)) 87662306a36Sopenharmony_ci return; 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci dec->iso_stream_count--; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci if (!dec->iso_stream_count) { 88162306a36Sopenharmony_ci for (i = 0; i < ISO_BUF_COUNT; i++) 88262306a36Sopenharmony_ci usb_kill_urb(dec->iso_urb[i]); 88362306a36Sopenharmony_ci } 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci mutex_unlock(&dec->iso_mutex); 88662306a36Sopenharmony_ci} 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci/* Setting the interface of the DEC tends to take down the USB communications 88962306a36Sopenharmony_ci * for a short period, so it's important not to call this function just before 89062306a36Sopenharmony_ci * trying to talk to it. 89162306a36Sopenharmony_ci */ 89262306a36Sopenharmony_cistatic int ttusb_dec_set_interface(struct ttusb_dec *dec, 89362306a36Sopenharmony_ci enum ttusb_dec_interface interface) 89462306a36Sopenharmony_ci{ 89562306a36Sopenharmony_ci int result = 0; 89662306a36Sopenharmony_ci u8 b[] = { 0x05 }; 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci if (interface != dec->interface) { 89962306a36Sopenharmony_ci switch (interface) { 90062306a36Sopenharmony_ci case TTUSB_DEC_INTERFACE_INITIAL: 90162306a36Sopenharmony_ci result = usb_set_interface(dec->udev, 0, 0); 90262306a36Sopenharmony_ci break; 90362306a36Sopenharmony_ci case TTUSB_DEC_INTERFACE_IN: 90462306a36Sopenharmony_ci result = ttusb_dec_send_command(dec, 0x80, sizeof(b), 90562306a36Sopenharmony_ci b, NULL, NULL); 90662306a36Sopenharmony_ci if (result) 90762306a36Sopenharmony_ci return result; 90862306a36Sopenharmony_ci result = usb_set_interface(dec->udev, 0, 8); 90962306a36Sopenharmony_ci break; 91062306a36Sopenharmony_ci case TTUSB_DEC_INTERFACE_OUT: 91162306a36Sopenharmony_ci result = usb_set_interface(dec->udev, 0, 1); 91262306a36Sopenharmony_ci break; 91362306a36Sopenharmony_ci } 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci if (result) 91662306a36Sopenharmony_ci return result; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci dec->interface = interface; 91962306a36Sopenharmony_ci } 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci return 0; 92262306a36Sopenharmony_ci} 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_cistatic int ttusb_dec_start_iso_xfer(struct ttusb_dec *dec) 92562306a36Sopenharmony_ci{ 92662306a36Sopenharmony_ci int i, result; 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci dprintk("%s\n", __func__); 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci if (mutex_lock_interruptible(&dec->iso_mutex)) 93162306a36Sopenharmony_ci return -EAGAIN; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci if (!dec->iso_stream_count) { 93462306a36Sopenharmony_ci ttusb_dec_setup_urbs(dec); 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci dec->packet_state = 0; 93762306a36Sopenharmony_ci dec->v_pes_postbytes = 0; 93862306a36Sopenharmony_ci dec->next_packet_id = 0; 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci for (i = 0; i < ISO_BUF_COUNT; i++) { 94162306a36Sopenharmony_ci if ((result = usb_submit_urb(dec->iso_urb[i], 94262306a36Sopenharmony_ci GFP_ATOMIC))) { 94362306a36Sopenharmony_ci printk("%s: failed urb submission %d: error %d\n", 94462306a36Sopenharmony_ci __func__, i, result); 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci while (i) { 94762306a36Sopenharmony_ci usb_kill_urb(dec->iso_urb[i - 1]); 94862306a36Sopenharmony_ci i--; 94962306a36Sopenharmony_ci } 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci mutex_unlock(&dec->iso_mutex); 95262306a36Sopenharmony_ci return result; 95362306a36Sopenharmony_ci } 95462306a36Sopenharmony_ci } 95562306a36Sopenharmony_ci } 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci dec->iso_stream_count++; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci mutex_unlock(&dec->iso_mutex); 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci return 0; 96262306a36Sopenharmony_ci} 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_cistatic int ttusb_dec_start_ts_feed(struct dvb_demux_feed *dvbdmxfeed) 96562306a36Sopenharmony_ci{ 96662306a36Sopenharmony_ci struct dvb_demux *dvbdmx = dvbdmxfeed->demux; 96762306a36Sopenharmony_ci struct ttusb_dec *dec = dvbdmx->priv; 96862306a36Sopenharmony_ci u8 b0[] = { 0x05 }; 96962306a36Sopenharmony_ci int result = 0; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci dprintk("%s\n", __func__); 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci dprintk(" ts_type:"); 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci if (dvbdmxfeed->ts_type & TS_DECODER) 97662306a36Sopenharmony_ci dprintk(" TS_DECODER"); 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci if (dvbdmxfeed->ts_type & TS_PACKET) 97962306a36Sopenharmony_ci dprintk(" TS_PACKET"); 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci if (dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY) 98262306a36Sopenharmony_ci dprintk(" TS_PAYLOAD_ONLY"); 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci dprintk("\n"); 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci switch (dvbdmxfeed->pes_type) { 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci case DMX_PES_VIDEO: 98962306a36Sopenharmony_ci dprintk(" pes_type: DMX_PES_VIDEO\n"); 99062306a36Sopenharmony_ci dec->pid[DMX_PES_PCR] = dvbdmxfeed->pid; 99162306a36Sopenharmony_ci dec->pid[DMX_PES_VIDEO] = dvbdmxfeed->pid; 99262306a36Sopenharmony_ci dec->video_filter = dvbdmxfeed->filter; 99362306a36Sopenharmony_ci ttusb_dec_set_pids(dec); 99462306a36Sopenharmony_ci break; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci case DMX_PES_AUDIO: 99762306a36Sopenharmony_ci dprintk(" pes_type: DMX_PES_AUDIO\n"); 99862306a36Sopenharmony_ci dec->pid[DMX_PES_AUDIO] = dvbdmxfeed->pid; 99962306a36Sopenharmony_ci dec->audio_filter = dvbdmxfeed->filter; 100062306a36Sopenharmony_ci ttusb_dec_set_pids(dec); 100162306a36Sopenharmony_ci break; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci case DMX_PES_TELETEXT: 100462306a36Sopenharmony_ci dec->pid[DMX_PES_TELETEXT] = dvbdmxfeed->pid; 100562306a36Sopenharmony_ci dprintk(" pes_type: DMX_PES_TELETEXT(not supported)\n"); 100662306a36Sopenharmony_ci return -ENOSYS; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci case DMX_PES_PCR: 100962306a36Sopenharmony_ci dprintk(" pes_type: DMX_PES_PCR\n"); 101062306a36Sopenharmony_ci dec->pid[DMX_PES_PCR] = dvbdmxfeed->pid; 101162306a36Sopenharmony_ci ttusb_dec_set_pids(dec); 101262306a36Sopenharmony_ci break; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci case DMX_PES_OTHER: 101562306a36Sopenharmony_ci dprintk(" pes_type: DMX_PES_OTHER(not supported)\n"); 101662306a36Sopenharmony_ci return -ENOSYS; 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci default: 101962306a36Sopenharmony_ci dprintk(" pes_type: unknown (%d)\n", dvbdmxfeed->pes_type); 102062306a36Sopenharmony_ci return -EINVAL; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci } 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci result = ttusb_dec_send_command(dec, 0x80, sizeof(b0), b0, NULL, NULL); 102562306a36Sopenharmony_ci if (result) 102662306a36Sopenharmony_ci return result; 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci dec->pva_stream_count++; 102962306a36Sopenharmony_ci return ttusb_dec_start_iso_xfer(dec); 103062306a36Sopenharmony_ci} 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_cistatic int ttusb_dec_start_sec_feed(struct dvb_demux_feed *dvbdmxfeed) 103362306a36Sopenharmony_ci{ 103462306a36Sopenharmony_ci struct ttusb_dec *dec = dvbdmxfeed->demux->priv; 103562306a36Sopenharmony_ci u8 b0[] = { 0x00, 0x00, 0x00, 0x01, 103662306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 103762306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 103862306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 103962306a36Sopenharmony_ci 0x00, 0xff, 0x00, 0x00, 104062306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 104162306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 104262306a36Sopenharmony_ci 0x00 }; 104362306a36Sopenharmony_ci __be16 pid; 104462306a36Sopenharmony_ci u8 c[COMMAND_PACKET_SIZE]; 104562306a36Sopenharmony_ci int c_length; 104662306a36Sopenharmony_ci int result; 104762306a36Sopenharmony_ci struct filter_info *finfo; 104862306a36Sopenharmony_ci unsigned long flags; 104962306a36Sopenharmony_ci u8 x = 1; 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci dprintk("%s\n", __func__); 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci pid = htons(dvbdmxfeed->pid); 105462306a36Sopenharmony_ci memcpy(&b0[0], &pid, 2); 105562306a36Sopenharmony_ci memcpy(&b0[4], &x, 1); 105662306a36Sopenharmony_ci memcpy(&b0[5], &dvbdmxfeed->filter->filter.filter_value[0], 1); 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci result = ttusb_dec_send_command(dec, 0x60, sizeof(b0), b0, 105962306a36Sopenharmony_ci &c_length, c); 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci if (!result) { 106262306a36Sopenharmony_ci if (c_length == 2) { 106362306a36Sopenharmony_ci if (!(finfo = kmalloc(sizeof(struct filter_info), 106462306a36Sopenharmony_ci GFP_ATOMIC))) 106562306a36Sopenharmony_ci return -ENOMEM; 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci finfo->stream_id = c[1]; 106862306a36Sopenharmony_ci finfo->filter = dvbdmxfeed->filter; 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci spin_lock_irqsave(&dec->filter_info_list_lock, flags); 107162306a36Sopenharmony_ci list_add_tail(&finfo->filter_info_list, 107262306a36Sopenharmony_ci &dec->filter_info_list); 107362306a36Sopenharmony_ci spin_unlock_irqrestore(&dec->filter_info_list_lock, 107462306a36Sopenharmony_ci flags); 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci dvbdmxfeed->priv = finfo; 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci dec->filter_stream_count++; 107962306a36Sopenharmony_ci return ttusb_dec_start_iso_xfer(dec); 108062306a36Sopenharmony_ci } 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci return -EAGAIN; 108362306a36Sopenharmony_ci } else 108462306a36Sopenharmony_ci return result; 108562306a36Sopenharmony_ci} 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_cistatic int ttusb_dec_start_feed(struct dvb_demux_feed *dvbdmxfeed) 108862306a36Sopenharmony_ci{ 108962306a36Sopenharmony_ci struct dvb_demux *dvbdmx = dvbdmxfeed->demux; 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci dprintk("%s\n", __func__); 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci if (!dvbdmx->dmx.frontend) 109462306a36Sopenharmony_ci return -EINVAL; 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci dprintk(" pid: 0x%04X\n", dvbdmxfeed->pid); 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci switch (dvbdmxfeed->type) { 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci case DMX_TYPE_TS: 110162306a36Sopenharmony_ci return ttusb_dec_start_ts_feed(dvbdmxfeed); 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci case DMX_TYPE_SEC: 110462306a36Sopenharmony_ci return ttusb_dec_start_sec_feed(dvbdmxfeed); 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci default: 110762306a36Sopenharmony_ci dprintk(" type: unknown (%d)\n", dvbdmxfeed->type); 110862306a36Sopenharmony_ci return -EINVAL; 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci } 111162306a36Sopenharmony_ci} 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_cistatic int ttusb_dec_stop_ts_feed(struct dvb_demux_feed *dvbdmxfeed) 111462306a36Sopenharmony_ci{ 111562306a36Sopenharmony_ci struct ttusb_dec *dec = dvbdmxfeed->demux->priv; 111662306a36Sopenharmony_ci u8 b0[] = { 0x00 }; 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci ttusb_dec_send_command(dec, 0x81, sizeof(b0), b0, NULL, NULL); 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci dec->pva_stream_count--; 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci ttusb_dec_stop_iso_xfer(dec); 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci return 0; 112562306a36Sopenharmony_ci} 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_cistatic int ttusb_dec_stop_sec_feed(struct dvb_demux_feed *dvbdmxfeed) 112862306a36Sopenharmony_ci{ 112962306a36Sopenharmony_ci struct ttusb_dec *dec = dvbdmxfeed->demux->priv; 113062306a36Sopenharmony_ci u8 b0[] = { 0x00, 0x00 }; 113162306a36Sopenharmony_ci struct filter_info *finfo = dvbdmxfeed->priv; 113262306a36Sopenharmony_ci unsigned long flags; 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci b0[1] = finfo->stream_id; 113562306a36Sopenharmony_ci spin_lock_irqsave(&dec->filter_info_list_lock, flags); 113662306a36Sopenharmony_ci list_del(&finfo->filter_info_list); 113762306a36Sopenharmony_ci spin_unlock_irqrestore(&dec->filter_info_list_lock, flags); 113862306a36Sopenharmony_ci kfree(finfo); 113962306a36Sopenharmony_ci ttusb_dec_send_command(dec, 0x62, sizeof(b0), b0, NULL, NULL); 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci dec->filter_stream_count--; 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci ttusb_dec_stop_iso_xfer(dec); 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci return 0; 114662306a36Sopenharmony_ci} 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_cistatic int ttusb_dec_stop_feed(struct dvb_demux_feed *dvbdmxfeed) 114962306a36Sopenharmony_ci{ 115062306a36Sopenharmony_ci dprintk("%s\n", __func__); 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci switch (dvbdmxfeed->type) { 115362306a36Sopenharmony_ci case DMX_TYPE_TS: 115462306a36Sopenharmony_ci return ttusb_dec_stop_ts_feed(dvbdmxfeed); 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci case DMX_TYPE_SEC: 115762306a36Sopenharmony_ci return ttusb_dec_stop_sec_feed(dvbdmxfeed); 115862306a36Sopenharmony_ci } 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci return 0; 116162306a36Sopenharmony_ci} 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_cistatic void ttusb_dec_free_iso_urbs(struct ttusb_dec *dec) 116462306a36Sopenharmony_ci{ 116562306a36Sopenharmony_ci int i; 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci dprintk("%s\n", __func__); 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci for (i = 0; i < ISO_BUF_COUNT; i++) 117062306a36Sopenharmony_ci usb_free_urb(dec->iso_urb[i]); 117162306a36Sopenharmony_ci kfree(dec->iso_buffer); 117262306a36Sopenharmony_ci} 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_cistatic int ttusb_dec_alloc_iso_urbs(struct ttusb_dec *dec) 117562306a36Sopenharmony_ci{ 117662306a36Sopenharmony_ci int i; 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci dprintk("%s\n", __func__); 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci dec->iso_buffer = kcalloc(FRAMES_PER_ISO_BUF * ISO_BUF_COUNT, 118162306a36Sopenharmony_ci ISO_FRAME_SIZE, GFP_KERNEL); 118262306a36Sopenharmony_ci if (!dec->iso_buffer) 118362306a36Sopenharmony_ci return -ENOMEM; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci for (i = 0; i < ISO_BUF_COUNT; i++) { 118662306a36Sopenharmony_ci struct urb *urb; 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci if (!(urb = usb_alloc_urb(FRAMES_PER_ISO_BUF, GFP_ATOMIC))) { 118962306a36Sopenharmony_ci ttusb_dec_free_iso_urbs(dec); 119062306a36Sopenharmony_ci return -ENOMEM; 119162306a36Sopenharmony_ci } 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci dec->iso_urb[i] = urb; 119462306a36Sopenharmony_ci } 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci ttusb_dec_setup_urbs(dec); 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci return 0; 119962306a36Sopenharmony_ci} 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_cistatic void ttusb_dec_init_tasklet(struct ttusb_dec *dec) 120262306a36Sopenharmony_ci{ 120362306a36Sopenharmony_ci spin_lock_init(&dec->urb_frame_list_lock); 120462306a36Sopenharmony_ci INIT_LIST_HEAD(&dec->urb_frame_list); 120562306a36Sopenharmony_ci tasklet_setup(&dec->urb_tasklet, ttusb_dec_process_urb_frame_list); 120662306a36Sopenharmony_ci} 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_cistatic int ttusb_init_rc( struct ttusb_dec *dec) 120962306a36Sopenharmony_ci{ 121062306a36Sopenharmony_ci struct input_dev *input_dev; 121162306a36Sopenharmony_ci u8 b[] = { 0x00, 0x01 }; 121262306a36Sopenharmony_ci int i; 121362306a36Sopenharmony_ci int err; 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci usb_make_path(dec->udev, dec->rc_phys, sizeof(dec->rc_phys)); 121662306a36Sopenharmony_ci strlcat(dec->rc_phys, "/input0", sizeof(dec->rc_phys)); 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci input_dev = input_allocate_device(); 121962306a36Sopenharmony_ci if (!input_dev) 122062306a36Sopenharmony_ci return -ENOMEM; 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci input_dev->name = "ttusb_dec remote control"; 122362306a36Sopenharmony_ci input_dev->phys = dec->rc_phys; 122462306a36Sopenharmony_ci input_dev->evbit[0] = BIT_MASK(EV_KEY); 122562306a36Sopenharmony_ci input_dev->keycodesize = sizeof(u16); 122662306a36Sopenharmony_ci input_dev->keycodemax = 0x1a; 122762306a36Sopenharmony_ci input_dev->keycode = rc_keys; 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(rc_keys); i++) 123062306a36Sopenharmony_ci set_bit(rc_keys[i], input_dev->keybit); 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci err = input_register_device(input_dev); 123362306a36Sopenharmony_ci if (err) { 123462306a36Sopenharmony_ci input_free_device(input_dev); 123562306a36Sopenharmony_ci return err; 123662306a36Sopenharmony_ci } 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci dec->rc_input_dev = input_dev; 123962306a36Sopenharmony_ci if (usb_submit_urb(dec->irq_urb, GFP_KERNEL)) 124062306a36Sopenharmony_ci printk("%s: usb_submit_urb failed\n",__func__); 124162306a36Sopenharmony_ci /* enable irq pipe */ 124262306a36Sopenharmony_ci ttusb_dec_send_command(dec,0xb0,sizeof(b),b,NULL,NULL); 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci return 0; 124562306a36Sopenharmony_ci} 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_cistatic void ttusb_dec_init_v_pes(struct ttusb_dec *dec) 124862306a36Sopenharmony_ci{ 124962306a36Sopenharmony_ci dprintk("%s\n", __func__); 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci dec->v_pes[0] = 0x00; 125262306a36Sopenharmony_ci dec->v_pes[1] = 0x00; 125362306a36Sopenharmony_ci dec->v_pes[2] = 0x01; 125462306a36Sopenharmony_ci dec->v_pes[3] = 0xe0; 125562306a36Sopenharmony_ci} 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_cistatic int ttusb_dec_init_usb(struct ttusb_dec *dec) 125862306a36Sopenharmony_ci{ 125962306a36Sopenharmony_ci int result; 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci dprintk("%s\n", __func__); 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci mutex_init(&dec->usb_mutex); 126462306a36Sopenharmony_ci mutex_init(&dec->iso_mutex); 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci dec->command_pipe = usb_sndbulkpipe(dec->udev, COMMAND_PIPE); 126762306a36Sopenharmony_ci dec->result_pipe = usb_rcvbulkpipe(dec->udev, RESULT_PIPE); 126862306a36Sopenharmony_ci dec->in_pipe = usb_rcvisocpipe(dec->udev, IN_PIPE); 126962306a36Sopenharmony_ci dec->out_pipe = usb_sndisocpipe(dec->udev, OUT_PIPE); 127062306a36Sopenharmony_ci dec->irq_pipe = usb_rcvintpipe(dec->udev, IRQ_PIPE); 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci if(enable_rc) { 127362306a36Sopenharmony_ci dec->irq_urb = usb_alloc_urb(0, GFP_KERNEL); 127462306a36Sopenharmony_ci if(!dec->irq_urb) { 127562306a36Sopenharmony_ci return -ENOMEM; 127662306a36Sopenharmony_ci } 127762306a36Sopenharmony_ci dec->irq_buffer = usb_alloc_coherent(dec->udev,IRQ_PACKET_SIZE, 127862306a36Sopenharmony_ci GFP_KERNEL, &dec->irq_dma_handle); 127962306a36Sopenharmony_ci if(!dec->irq_buffer) { 128062306a36Sopenharmony_ci usb_free_urb(dec->irq_urb); 128162306a36Sopenharmony_ci return -ENOMEM; 128262306a36Sopenharmony_ci } 128362306a36Sopenharmony_ci usb_fill_int_urb(dec->irq_urb, dec->udev,dec->irq_pipe, 128462306a36Sopenharmony_ci dec->irq_buffer, IRQ_PACKET_SIZE, 128562306a36Sopenharmony_ci ttusb_dec_handle_irq, dec, 1); 128662306a36Sopenharmony_ci dec->irq_urb->transfer_dma = dec->irq_dma_handle; 128762306a36Sopenharmony_ci dec->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 128862306a36Sopenharmony_ci } 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci result = ttusb_dec_alloc_iso_urbs(dec); 129162306a36Sopenharmony_ci if (result) { 129262306a36Sopenharmony_ci usb_free_urb(dec->irq_urb); 129362306a36Sopenharmony_ci usb_free_coherent(dec->udev, IRQ_PACKET_SIZE, 129462306a36Sopenharmony_ci dec->irq_buffer, dec->irq_dma_handle); 129562306a36Sopenharmony_ci } 129662306a36Sopenharmony_ci return result; 129762306a36Sopenharmony_ci} 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_cistatic int ttusb_dec_boot_dsp(struct ttusb_dec *dec) 130062306a36Sopenharmony_ci{ 130162306a36Sopenharmony_ci int i, j, actual_len, result, size, trans_count; 130262306a36Sopenharmony_ci u8 b0[] = { 0x00, 0x00, 0x00, 0x00, 130362306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 130462306a36Sopenharmony_ci 0x61, 0x00 }; 130562306a36Sopenharmony_ci u8 b1[] = { 0x61 }; 130662306a36Sopenharmony_ci u8 *b; 130762306a36Sopenharmony_ci char idstring[21]; 130862306a36Sopenharmony_ci const u8 *firmware = NULL; 130962306a36Sopenharmony_ci size_t firmware_size = 0; 131062306a36Sopenharmony_ci u16 firmware_csum = 0; 131162306a36Sopenharmony_ci __be16 firmware_csum_ns; 131262306a36Sopenharmony_ci __be32 firmware_size_nl; 131362306a36Sopenharmony_ci u32 crc32_csum, crc32_check; 131462306a36Sopenharmony_ci __be32 tmp; 131562306a36Sopenharmony_ci const struct firmware *fw_entry = NULL; 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci dprintk("%s\n", __func__); 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci result = request_firmware(&fw_entry, dec->firmware_name, &dec->udev->dev); 132062306a36Sopenharmony_ci if (result) { 132162306a36Sopenharmony_ci printk(KERN_ERR "%s: Firmware (%s) unavailable.\n", 132262306a36Sopenharmony_ci __func__, dec->firmware_name); 132362306a36Sopenharmony_ci return result; 132462306a36Sopenharmony_ci } 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci firmware = fw_entry->data; 132762306a36Sopenharmony_ci firmware_size = fw_entry->size; 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci if (firmware_size < 60) { 133062306a36Sopenharmony_ci printk("%s: firmware size too small for DSP code (%zu < 60).\n", 133162306a36Sopenharmony_ci __func__, firmware_size); 133262306a36Sopenharmony_ci release_firmware(fw_entry); 133362306a36Sopenharmony_ci return -ENOENT; 133462306a36Sopenharmony_ci } 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci /* a 32 bit checksum over the first 56 bytes of the DSP Code is stored 133762306a36Sopenharmony_ci at offset 56 of file, so use it to check if the firmware file is 133862306a36Sopenharmony_ci valid. */ 133962306a36Sopenharmony_ci crc32_csum = crc32(~0L, firmware, 56) ^ ~0L; 134062306a36Sopenharmony_ci memcpy(&tmp, &firmware[56], 4); 134162306a36Sopenharmony_ci crc32_check = ntohl(tmp); 134262306a36Sopenharmony_ci if (crc32_csum != crc32_check) { 134362306a36Sopenharmony_ci printk("%s: crc32 check of DSP code failed (calculated 0x%08x != 0x%08x in file), file invalid.\n", 134462306a36Sopenharmony_ci __func__, crc32_csum, crc32_check); 134562306a36Sopenharmony_ci release_firmware(fw_entry); 134662306a36Sopenharmony_ci return -ENOENT; 134762306a36Sopenharmony_ci } 134862306a36Sopenharmony_ci memcpy(idstring, &firmware[36], 20); 134962306a36Sopenharmony_ci idstring[20] = '\0'; 135062306a36Sopenharmony_ci printk(KERN_INFO "ttusb_dec: found DSP code \"%s\".\n", idstring); 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci firmware_size_nl = htonl(firmware_size); 135362306a36Sopenharmony_ci memcpy(b0, &firmware_size_nl, 4); 135462306a36Sopenharmony_ci firmware_csum = crc16(~0, firmware, firmware_size) ^ ~0; 135562306a36Sopenharmony_ci firmware_csum_ns = htons(firmware_csum); 135662306a36Sopenharmony_ci memcpy(&b0[6], &firmware_csum_ns, 2); 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci result = ttusb_dec_send_command(dec, 0x41, sizeof(b0), b0, NULL, NULL); 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci if (result) { 136162306a36Sopenharmony_ci release_firmware(fw_entry); 136262306a36Sopenharmony_ci return result; 136362306a36Sopenharmony_ci } 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci trans_count = 0; 136662306a36Sopenharmony_ci j = 0; 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci b = kmalloc(ARM_PACKET_SIZE, GFP_KERNEL); 136962306a36Sopenharmony_ci if (b == NULL) { 137062306a36Sopenharmony_ci release_firmware(fw_entry); 137162306a36Sopenharmony_ci return -ENOMEM; 137262306a36Sopenharmony_ci } 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci for (i = 0; i < firmware_size; i += COMMAND_PACKET_SIZE) { 137562306a36Sopenharmony_ci size = firmware_size - i; 137662306a36Sopenharmony_ci if (size > COMMAND_PACKET_SIZE) 137762306a36Sopenharmony_ci size = COMMAND_PACKET_SIZE; 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci b[j + 0] = 0xaa; 138062306a36Sopenharmony_ci b[j + 1] = trans_count++; 138162306a36Sopenharmony_ci b[j + 2] = 0xf0; 138262306a36Sopenharmony_ci b[j + 3] = size; 138362306a36Sopenharmony_ci memcpy(&b[j + 4], &firmware[i], size); 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci j += COMMAND_PACKET_SIZE + 4; 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci if (j >= ARM_PACKET_SIZE) { 138862306a36Sopenharmony_ci result = usb_bulk_msg(dec->udev, dec->command_pipe, b, 138962306a36Sopenharmony_ci ARM_PACKET_SIZE, &actual_len, 139062306a36Sopenharmony_ci 100); 139162306a36Sopenharmony_ci j = 0; 139262306a36Sopenharmony_ci } else if (size < COMMAND_PACKET_SIZE) { 139362306a36Sopenharmony_ci result = usb_bulk_msg(dec->udev, dec->command_pipe, b, 139462306a36Sopenharmony_ci j - COMMAND_PACKET_SIZE + size, 139562306a36Sopenharmony_ci &actual_len, 100); 139662306a36Sopenharmony_ci } 139762306a36Sopenharmony_ci } 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci result = ttusb_dec_send_command(dec, 0x43, sizeof(b1), b1, NULL, NULL); 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci release_firmware(fw_entry); 140262306a36Sopenharmony_ci kfree(b); 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci return result; 140562306a36Sopenharmony_ci} 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_cistatic int ttusb_dec_init_stb(struct ttusb_dec *dec) 140862306a36Sopenharmony_ci{ 140962306a36Sopenharmony_ci int result; 141062306a36Sopenharmony_ci unsigned int mode = 0, model = 0, version = 0; 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci dprintk("%s\n", __func__); 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci result = ttusb_dec_get_stb_state(dec, &mode, &model, &version); 141562306a36Sopenharmony_ci if (result) 141662306a36Sopenharmony_ci return result; 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci if (!mode) { 141962306a36Sopenharmony_ci if (version == 0xABCDEFAB) 142062306a36Sopenharmony_ci printk(KERN_INFO "ttusb_dec: no version info in Firmware\n"); 142162306a36Sopenharmony_ci else 142262306a36Sopenharmony_ci printk(KERN_INFO "ttusb_dec: Firmware %x.%02x%c%c\n", 142362306a36Sopenharmony_ci version >> 24, (version >> 16) & 0xff, 142462306a36Sopenharmony_ci (version >> 8) & 0xff, version & 0xff); 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci result = ttusb_dec_boot_dsp(dec); 142762306a36Sopenharmony_ci if (result) 142862306a36Sopenharmony_ci return result; 142962306a36Sopenharmony_ci } else { 143062306a36Sopenharmony_ci /* We can't trust the USB IDs that some firmwares 143162306a36Sopenharmony_ci give the box */ 143262306a36Sopenharmony_ci switch (model) { 143362306a36Sopenharmony_ci case 0x00070001: 143462306a36Sopenharmony_ci case 0x00070008: 143562306a36Sopenharmony_ci case 0x0007000c: 143662306a36Sopenharmony_ci ttusb_dec_set_model(dec, TTUSB_DEC3000S); 143762306a36Sopenharmony_ci break; 143862306a36Sopenharmony_ci case 0x00070009: 143962306a36Sopenharmony_ci case 0x00070013: 144062306a36Sopenharmony_ci ttusb_dec_set_model(dec, TTUSB_DEC2000T); 144162306a36Sopenharmony_ci break; 144262306a36Sopenharmony_ci case 0x00070011: 144362306a36Sopenharmony_ci ttusb_dec_set_model(dec, TTUSB_DEC2540T); 144462306a36Sopenharmony_ci break; 144562306a36Sopenharmony_ci default: 144662306a36Sopenharmony_ci printk(KERN_ERR "%s: unknown model returned by firmware (%08x) - please report\n", 144762306a36Sopenharmony_ci __func__, model); 144862306a36Sopenharmony_ci return -ENOENT; 144962306a36Sopenharmony_ci } 145062306a36Sopenharmony_ci if (version >= 0x01770000) 145162306a36Sopenharmony_ci dec->can_playback = 1; 145262306a36Sopenharmony_ci } 145362306a36Sopenharmony_ci return 0; 145462306a36Sopenharmony_ci} 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_cistatic int ttusb_dec_init_dvb(struct ttusb_dec *dec) 145762306a36Sopenharmony_ci{ 145862306a36Sopenharmony_ci int result; 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci dprintk("%s\n", __func__); 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci if ((result = dvb_register_adapter(&dec->adapter, 146362306a36Sopenharmony_ci dec->model_name, THIS_MODULE, 146462306a36Sopenharmony_ci &dec->udev->dev, 146562306a36Sopenharmony_ci adapter_nr)) < 0) { 146662306a36Sopenharmony_ci printk("%s: dvb_register_adapter failed: error %d\n", 146762306a36Sopenharmony_ci __func__, result); 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci return result; 147062306a36Sopenharmony_ci } 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci dec->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci dec->demux.priv = (void *)dec; 147562306a36Sopenharmony_ci dec->demux.filternum = 31; 147662306a36Sopenharmony_ci dec->demux.feednum = 31; 147762306a36Sopenharmony_ci dec->demux.start_feed = ttusb_dec_start_feed; 147862306a36Sopenharmony_ci dec->demux.stop_feed = ttusb_dec_stop_feed; 147962306a36Sopenharmony_ci dec->demux.write_to_decoder = NULL; 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci if ((result = dvb_dmx_init(&dec->demux)) < 0) { 148262306a36Sopenharmony_ci printk("%s: dvb_dmx_init failed: error %d\n", __func__, 148362306a36Sopenharmony_ci result); 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci dvb_unregister_adapter(&dec->adapter); 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci return result; 148862306a36Sopenharmony_ci } 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci dec->dmxdev.filternum = 32; 149162306a36Sopenharmony_ci dec->dmxdev.demux = &dec->demux.dmx; 149262306a36Sopenharmony_ci dec->dmxdev.capabilities = 0; 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci if ((result = dvb_dmxdev_init(&dec->dmxdev, &dec->adapter)) < 0) { 149562306a36Sopenharmony_ci printk("%s: dvb_dmxdev_init failed: error %d\n", 149662306a36Sopenharmony_ci __func__, result); 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci dvb_dmx_release(&dec->demux); 149962306a36Sopenharmony_ci dvb_unregister_adapter(&dec->adapter); 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci return result; 150262306a36Sopenharmony_ci } 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci dec->frontend.source = DMX_FRONTEND_0; 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci if ((result = dec->demux.dmx.add_frontend(&dec->demux.dmx, 150762306a36Sopenharmony_ci &dec->frontend)) < 0) { 150862306a36Sopenharmony_ci printk("%s: dvb_dmx_init failed: error %d\n", __func__, 150962306a36Sopenharmony_ci result); 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci dvb_dmxdev_release(&dec->dmxdev); 151262306a36Sopenharmony_ci dvb_dmx_release(&dec->demux); 151362306a36Sopenharmony_ci dvb_unregister_adapter(&dec->adapter); 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci return result; 151662306a36Sopenharmony_ci } 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci if ((result = dec->demux.dmx.connect_frontend(&dec->demux.dmx, 151962306a36Sopenharmony_ci &dec->frontend)) < 0) { 152062306a36Sopenharmony_ci printk("%s: dvb_dmx_init failed: error %d\n", __func__, 152162306a36Sopenharmony_ci result); 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend); 152462306a36Sopenharmony_ci dvb_dmxdev_release(&dec->dmxdev); 152562306a36Sopenharmony_ci dvb_dmx_release(&dec->demux); 152662306a36Sopenharmony_ci dvb_unregister_adapter(&dec->adapter); 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci return result; 152962306a36Sopenharmony_ci } 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci dvb_net_init(&dec->adapter, &dec->dvb_net, &dec->demux.dmx); 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci return 0; 153462306a36Sopenharmony_ci} 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_cistatic void ttusb_dec_exit_dvb(struct ttusb_dec *dec) 153762306a36Sopenharmony_ci{ 153862306a36Sopenharmony_ci dprintk("%s\n", __func__); 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci dvb_net_release(&dec->dvb_net); 154162306a36Sopenharmony_ci dec->demux.dmx.close(&dec->demux.dmx); 154262306a36Sopenharmony_ci dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend); 154362306a36Sopenharmony_ci dvb_dmxdev_release(&dec->dmxdev); 154462306a36Sopenharmony_ci dvb_dmx_release(&dec->demux); 154562306a36Sopenharmony_ci if (dec->fe) { 154662306a36Sopenharmony_ci dvb_unregister_frontend(dec->fe); 154762306a36Sopenharmony_ci dvb_frontend_detach(dec->fe); 154862306a36Sopenharmony_ci } 154962306a36Sopenharmony_ci dvb_unregister_adapter(&dec->adapter); 155062306a36Sopenharmony_ci} 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_cistatic void ttusb_dec_exit_rc(struct ttusb_dec *dec) 155362306a36Sopenharmony_ci{ 155462306a36Sopenharmony_ci dprintk("%s\n", __func__); 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci if (dec->rc_input_dev) { 155762306a36Sopenharmony_ci input_unregister_device(dec->rc_input_dev); 155862306a36Sopenharmony_ci dec->rc_input_dev = NULL; 155962306a36Sopenharmony_ci } 156062306a36Sopenharmony_ci} 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_cistatic void ttusb_dec_exit_usb(struct ttusb_dec *dec) 156462306a36Sopenharmony_ci{ 156562306a36Sopenharmony_ci int i; 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci dprintk("%s\n", __func__); 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ci if (enable_rc) { 157062306a36Sopenharmony_ci /* we have to check whether the irq URB is already submitted. 157162306a36Sopenharmony_ci * As the irq is submitted after the interface is changed, 157262306a36Sopenharmony_ci * this is the best method i figured out. 157362306a36Sopenharmony_ci * Any others?*/ 157462306a36Sopenharmony_ci if (dec->interface == TTUSB_DEC_INTERFACE_IN) 157562306a36Sopenharmony_ci usb_kill_urb(dec->irq_urb); 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_ci usb_free_urb(dec->irq_urb); 157862306a36Sopenharmony_ci 157962306a36Sopenharmony_ci usb_free_coherent(dec->udev, IRQ_PACKET_SIZE, 158062306a36Sopenharmony_ci dec->irq_buffer, dec->irq_dma_handle); 158162306a36Sopenharmony_ci } 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci dec->iso_stream_count = 0; 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci for (i = 0; i < ISO_BUF_COUNT; i++) 158662306a36Sopenharmony_ci usb_kill_urb(dec->iso_urb[i]); 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci ttusb_dec_free_iso_urbs(dec); 158962306a36Sopenharmony_ci} 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_cistatic void ttusb_dec_exit_tasklet(struct ttusb_dec *dec) 159262306a36Sopenharmony_ci{ 159362306a36Sopenharmony_ci struct list_head *item; 159462306a36Sopenharmony_ci struct urb_frame *frame; 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci tasklet_kill(&dec->urb_tasklet); 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci while ((item = dec->urb_frame_list.next) != &dec->urb_frame_list) { 159962306a36Sopenharmony_ci frame = list_entry(item, struct urb_frame, urb_frame_list); 160062306a36Sopenharmony_ci list_del(&frame->urb_frame_list); 160162306a36Sopenharmony_ci kfree(frame); 160262306a36Sopenharmony_ci } 160362306a36Sopenharmony_ci} 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_cistatic void ttusb_dec_init_filters(struct ttusb_dec *dec) 160662306a36Sopenharmony_ci{ 160762306a36Sopenharmony_ci INIT_LIST_HEAD(&dec->filter_info_list); 160862306a36Sopenharmony_ci spin_lock_init(&dec->filter_info_list_lock); 160962306a36Sopenharmony_ci} 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_cistatic void ttusb_dec_exit_filters(struct ttusb_dec *dec) 161262306a36Sopenharmony_ci{ 161362306a36Sopenharmony_ci struct list_head *item; 161462306a36Sopenharmony_ci struct filter_info *finfo; 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ci while ((item = dec->filter_info_list.next) != &dec->filter_info_list) { 161762306a36Sopenharmony_ci finfo = list_entry(item, struct filter_info, filter_info_list); 161862306a36Sopenharmony_ci list_del(&finfo->filter_info_list); 161962306a36Sopenharmony_ci kfree(finfo); 162062306a36Sopenharmony_ci } 162162306a36Sopenharmony_ci} 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_cistatic int fe_send_command(struct dvb_frontend* fe, const u8 command, 162462306a36Sopenharmony_ci int param_length, const u8 params[], 162562306a36Sopenharmony_ci int *result_length, u8 cmd_result[]) 162662306a36Sopenharmony_ci{ 162762306a36Sopenharmony_ci struct ttusb_dec* dec = fe->dvb->priv; 162862306a36Sopenharmony_ci return ttusb_dec_send_command(dec, command, param_length, params, result_length, cmd_result); 162962306a36Sopenharmony_ci} 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_cistatic const struct ttusbdecfe_config fe_config = { 163262306a36Sopenharmony_ci .send_command = fe_send_command 163362306a36Sopenharmony_ci}; 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_cistatic int ttusb_dec_probe(struct usb_interface *intf, 163662306a36Sopenharmony_ci const struct usb_device_id *id) 163762306a36Sopenharmony_ci{ 163862306a36Sopenharmony_ci struct usb_device *udev; 163962306a36Sopenharmony_ci struct ttusb_dec *dec; 164062306a36Sopenharmony_ci int result; 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci dprintk("%s\n", __func__); 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_ci udev = interface_to_usbdev(intf); 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_ci if (!(dec = kzalloc(sizeof(struct ttusb_dec), GFP_KERNEL))) { 164762306a36Sopenharmony_ci printk("%s: couldn't allocate memory.\n", __func__); 164862306a36Sopenharmony_ci return -ENOMEM; 164962306a36Sopenharmony_ci } 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ci usb_set_intfdata(intf, (void *)dec); 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci switch (id->idProduct) { 165462306a36Sopenharmony_ci case 0x1006: 165562306a36Sopenharmony_ci ttusb_dec_set_model(dec, TTUSB_DEC3000S); 165662306a36Sopenharmony_ci break; 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci case 0x1008: 165962306a36Sopenharmony_ci ttusb_dec_set_model(dec, TTUSB_DEC2000T); 166062306a36Sopenharmony_ci break; 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_ci case 0x1009: 166362306a36Sopenharmony_ci ttusb_dec_set_model(dec, TTUSB_DEC2540T); 166462306a36Sopenharmony_ci break; 166562306a36Sopenharmony_ci } 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci dec->udev = udev; 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_ci result = ttusb_dec_init_usb(dec); 167062306a36Sopenharmony_ci if (result) 167162306a36Sopenharmony_ci goto err_usb; 167262306a36Sopenharmony_ci result = ttusb_dec_init_stb(dec); 167362306a36Sopenharmony_ci if (result) 167462306a36Sopenharmony_ci goto err_stb; 167562306a36Sopenharmony_ci result = ttusb_dec_init_dvb(dec); 167662306a36Sopenharmony_ci if (result) 167762306a36Sopenharmony_ci goto err_stb; 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_ci dec->adapter.priv = dec; 168062306a36Sopenharmony_ci switch (id->idProduct) { 168162306a36Sopenharmony_ci case 0x1006: 168262306a36Sopenharmony_ci dec->fe = ttusbdecfe_dvbs_attach(&fe_config); 168362306a36Sopenharmony_ci break; 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ci case 0x1008: 168662306a36Sopenharmony_ci case 0x1009: 168762306a36Sopenharmony_ci dec->fe = ttusbdecfe_dvbt_attach(&fe_config); 168862306a36Sopenharmony_ci break; 168962306a36Sopenharmony_ci } 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_ci if (dec->fe == NULL) { 169262306a36Sopenharmony_ci printk("dvb-ttusb-dec: A frontend driver was not found for device [%04x:%04x]\n", 169362306a36Sopenharmony_ci le16_to_cpu(dec->udev->descriptor.idVendor), 169462306a36Sopenharmony_ci le16_to_cpu(dec->udev->descriptor.idProduct)); 169562306a36Sopenharmony_ci } else { 169662306a36Sopenharmony_ci if (dvb_register_frontend(&dec->adapter, dec->fe)) { 169762306a36Sopenharmony_ci printk("budget-ci: Frontend registration failed!\n"); 169862306a36Sopenharmony_ci if (dec->fe->ops.release) 169962306a36Sopenharmony_ci dec->fe->ops.release(dec->fe); 170062306a36Sopenharmony_ci dec->fe = NULL; 170162306a36Sopenharmony_ci } 170262306a36Sopenharmony_ci } 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_ci ttusb_dec_init_v_pes(dec); 170562306a36Sopenharmony_ci ttusb_dec_init_filters(dec); 170662306a36Sopenharmony_ci ttusb_dec_init_tasklet(dec); 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci dec->active = 1; 170962306a36Sopenharmony_ci 171062306a36Sopenharmony_ci ttusb_dec_set_interface(dec, TTUSB_DEC_INTERFACE_IN); 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ci if (enable_rc) 171362306a36Sopenharmony_ci ttusb_init_rc(dec); 171462306a36Sopenharmony_ci 171562306a36Sopenharmony_ci return 0; 171662306a36Sopenharmony_cierr_stb: 171762306a36Sopenharmony_ci ttusb_dec_exit_usb(dec); 171862306a36Sopenharmony_cierr_usb: 171962306a36Sopenharmony_ci kfree(dec); 172062306a36Sopenharmony_ci return result; 172162306a36Sopenharmony_ci} 172262306a36Sopenharmony_ci 172362306a36Sopenharmony_cistatic void ttusb_dec_disconnect(struct usb_interface *intf) 172462306a36Sopenharmony_ci{ 172562306a36Sopenharmony_ci struct ttusb_dec *dec = usb_get_intfdata(intf); 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_ci usb_set_intfdata(intf, NULL); 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_ci dprintk("%s\n", __func__); 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci if (dec->active) { 173262306a36Sopenharmony_ci ttusb_dec_exit_tasklet(dec); 173362306a36Sopenharmony_ci ttusb_dec_exit_filters(dec); 173462306a36Sopenharmony_ci if(enable_rc) 173562306a36Sopenharmony_ci ttusb_dec_exit_rc(dec); 173662306a36Sopenharmony_ci ttusb_dec_exit_usb(dec); 173762306a36Sopenharmony_ci ttusb_dec_exit_dvb(dec); 173862306a36Sopenharmony_ci } 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ci kfree(dec); 174162306a36Sopenharmony_ci} 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_cistatic void ttusb_dec_set_model(struct ttusb_dec *dec, 174462306a36Sopenharmony_ci enum ttusb_dec_model model) 174562306a36Sopenharmony_ci{ 174662306a36Sopenharmony_ci dec->model = model; 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_ci switch (model) { 174962306a36Sopenharmony_ci case TTUSB_DEC2000T: 175062306a36Sopenharmony_ci dec->model_name = "DEC2000-t"; 175162306a36Sopenharmony_ci dec->firmware_name = "dvb-ttusb-dec-2000t.fw"; 175262306a36Sopenharmony_ci break; 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci case TTUSB_DEC2540T: 175562306a36Sopenharmony_ci dec->model_name = "DEC2540-t"; 175662306a36Sopenharmony_ci dec->firmware_name = "dvb-ttusb-dec-2540t.fw"; 175762306a36Sopenharmony_ci break; 175862306a36Sopenharmony_ci 175962306a36Sopenharmony_ci case TTUSB_DEC3000S: 176062306a36Sopenharmony_ci dec->model_name = "DEC3000-s"; 176162306a36Sopenharmony_ci dec->firmware_name = "dvb-ttusb-dec-3000s.fw"; 176262306a36Sopenharmony_ci break; 176362306a36Sopenharmony_ci } 176462306a36Sopenharmony_ci} 176562306a36Sopenharmony_ci 176662306a36Sopenharmony_cistatic const struct usb_device_id ttusb_dec_table[] = { 176762306a36Sopenharmony_ci {USB_DEVICE(0x0b48, 0x1006)}, /* DEC3000-s */ 176862306a36Sopenharmony_ci /*{USB_DEVICE(0x0b48, 0x1007)}, Unconfirmed */ 176962306a36Sopenharmony_ci {USB_DEVICE(0x0b48, 0x1008)}, /* DEC2000-t */ 177062306a36Sopenharmony_ci {USB_DEVICE(0x0b48, 0x1009)}, /* DEC2540-t */ 177162306a36Sopenharmony_ci {} 177262306a36Sopenharmony_ci}; 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_cistatic struct usb_driver ttusb_dec_driver = { 177562306a36Sopenharmony_ci .name = "ttusb-dec", 177662306a36Sopenharmony_ci .probe = ttusb_dec_probe, 177762306a36Sopenharmony_ci .disconnect = ttusb_dec_disconnect, 177862306a36Sopenharmony_ci .id_table = ttusb_dec_table, 177962306a36Sopenharmony_ci}; 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_cimodule_usb_driver(ttusb_dec_driver); 178262306a36Sopenharmony_ci 178362306a36Sopenharmony_ciMODULE_AUTHOR("Alex Woods <linux-dvb@giblets.org>"); 178462306a36Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_NAME); 178562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 178662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, ttusb_dec_table); 1787