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