1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2786baecfSMauro Carvalho Chehab /*
3786baecfSMauro Carvalho Chehab  * TTUSB DEC Driver
4786baecfSMauro Carvalho Chehab  *
5786baecfSMauro Carvalho Chehab  * Copyright (C) 2003-2004 Alex Woods <linux-dvb@giblets.org>
6786baecfSMauro Carvalho Chehab  * IR support by Peter Beutner <p.beutner@gmx.net>
7786baecfSMauro Carvalho Chehab  */
8786baecfSMauro Carvalho Chehab 
9786baecfSMauro Carvalho Chehab #include <linux/list.h>
10786baecfSMauro Carvalho Chehab #include <linux/module.h>
11786baecfSMauro Carvalho Chehab #include <linux/pci.h>
12786baecfSMauro Carvalho Chehab #include <linux/slab.h>
13786baecfSMauro Carvalho Chehab #include <linux/spinlock.h>
14786baecfSMauro Carvalho Chehab #include <linux/usb.h>
15786baecfSMauro Carvalho Chehab #include <linux/interrupt.h>
16786baecfSMauro Carvalho Chehab #include <linux/firmware.h>
17786baecfSMauro Carvalho Chehab #include <linux/crc32.h>
18786baecfSMauro Carvalho Chehab #include <linux/init.h>
19786baecfSMauro Carvalho Chehab #include <linux/input.h>
20786baecfSMauro Carvalho Chehab 
21786baecfSMauro Carvalho Chehab #include <linux/mutex.h>
22786baecfSMauro Carvalho Chehab 
23fada1935SMauro Carvalho Chehab #include <media/dmxdev.h>
24fada1935SMauro Carvalho Chehab #include <media/dvb_demux.h>
25fada1935SMauro Carvalho Chehab #include <media/dvb_frontend.h>
26fada1935SMauro Carvalho Chehab #include <media/dvb_net.h>
27786baecfSMauro Carvalho Chehab #include "ttusbdecfe.h"
28786baecfSMauro Carvalho Chehab 
29786baecfSMauro Carvalho Chehab static int debug;
30786baecfSMauro Carvalho Chehab static int output_pva;
31786baecfSMauro Carvalho Chehab static int enable_rc;
32786baecfSMauro Carvalho Chehab 
33786baecfSMauro Carvalho Chehab module_param(debug, int, 0644);
34786baecfSMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
35786baecfSMauro Carvalho Chehab module_param(output_pva, int, 0444);
36786baecfSMauro Carvalho Chehab MODULE_PARM_DESC(output_pva, "Output PVA from dvr device (default:off)");
37786baecfSMauro Carvalho Chehab module_param(enable_rc, int, 0644);
38786baecfSMauro Carvalho Chehab MODULE_PARM_DESC(enable_rc, "Turn on/off IR remote control(default: off)");
39786baecfSMauro Carvalho Chehab 
40786baecfSMauro Carvalho Chehab DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
41786baecfSMauro Carvalho Chehab 
42786baecfSMauro Carvalho Chehab #define dprintk	if (debug) printk
43786baecfSMauro Carvalho Chehab 
44786baecfSMauro Carvalho Chehab #define DRIVER_NAME		"TechnoTrend/Hauppauge DEC USB"
45786baecfSMauro Carvalho Chehab 
46786baecfSMauro Carvalho Chehab #define COMMAND_PIPE		0x03
47786baecfSMauro Carvalho Chehab #define RESULT_PIPE		0x04
48786baecfSMauro Carvalho Chehab #define IN_PIPE			0x08
49786baecfSMauro Carvalho Chehab #define OUT_PIPE		0x07
50786baecfSMauro Carvalho Chehab #define IRQ_PIPE		0x0A
51786baecfSMauro Carvalho Chehab 
52786baecfSMauro Carvalho Chehab #define COMMAND_PACKET_SIZE	0x3c
53786baecfSMauro Carvalho Chehab #define ARM_PACKET_SIZE		0x1000
54786baecfSMauro Carvalho Chehab #define IRQ_PACKET_SIZE		0x8
55786baecfSMauro Carvalho Chehab 
56786baecfSMauro Carvalho Chehab #define ISO_BUF_COUNT		0x04
57786baecfSMauro Carvalho Chehab #define FRAMES_PER_ISO_BUF	0x04
58786baecfSMauro Carvalho Chehab #define ISO_FRAME_SIZE		0x0380
59786baecfSMauro Carvalho Chehab 
60786baecfSMauro Carvalho Chehab #define	MAX_PVA_LENGTH		6144
61786baecfSMauro Carvalho Chehab 
62786baecfSMauro Carvalho Chehab enum ttusb_dec_model {
63786baecfSMauro Carvalho Chehab 	TTUSB_DEC2000T,
64786baecfSMauro Carvalho Chehab 	TTUSB_DEC2540T,
65786baecfSMauro Carvalho Chehab 	TTUSB_DEC3000S
66786baecfSMauro Carvalho Chehab };
67786baecfSMauro Carvalho Chehab 
68786baecfSMauro Carvalho Chehab enum ttusb_dec_packet_type {
69786baecfSMauro Carvalho Chehab 	TTUSB_DEC_PACKET_PVA,
70786baecfSMauro Carvalho Chehab 	TTUSB_DEC_PACKET_SECTION,
71786baecfSMauro Carvalho Chehab 	TTUSB_DEC_PACKET_EMPTY
72786baecfSMauro Carvalho Chehab };
73786baecfSMauro Carvalho Chehab 
74786baecfSMauro Carvalho Chehab enum ttusb_dec_interface {
75786baecfSMauro Carvalho Chehab 	TTUSB_DEC_INTERFACE_INITIAL,
76786baecfSMauro Carvalho Chehab 	TTUSB_DEC_INTERFACE_IN,
77786baecfSMauro Carvalho Chehab 	TTUSB_DEC_INTERFACE_OUT
78786baecfSMauro Carvalho Chehab };
79786baecfSMauro Carvalho Chehab 
80b676e731SMauro Carvalho Chehab typedef int (dvb_filter_pes2ts_cb_t) (void *, unsigned char *);
81b676e731SMauro Carvalho Chehab 
82b676e731SMauro Carvalho Chehab struct dvb_filter_pes2ts {
83b676e731SMauro Carvalho Chehab 	unsigned char buf[188];
84b676e731SMauro Carvalho Chehab 	unsigned char cc;
85b676e731SMauro Carvalho Chehab 	dvb_filter_pes2ts_cb_t *cb;
86b676e731SMauro Carvalho Chehab 	void *priv;
87b676e731SMauro Carvalho Chehab };
88b676e731SMauro Carvalho Chehab 
89786baecfSMauro Carvalho Chehab struct ttusb_dec {
90786baecfSMauro Carvalho Chehab 	enum ttusb_dec_model		model;
91786baecfSMauro Carvalho Chehab 	char				*model_name;
92786baecfSMauro Carvalho Chehab 	char				*firmware_name;
93786baecfSMauro Carvalho Chehab 	int				can_playback;
94786baecfSMauro Carvalho Chehab 
95786baecfSMauro Carvalho Chehab 	/* DVB bits */
96786baecfSMauro Carvalho Chehab 	struct dvb_adapter		adapter;
97786baecfSMauro Carvalho Chehab 	struct dmxdev			dmxdev;
98786baecfSMauro Carvalho Chehab 	struct dvb_demux		demux;
99786baecfSMauro Carvalho Chehab 	struct dmx_frontend		frontend;
100786baecfSMauro Carvalho Chehab 	struct dvb_net			dvb_net;
101786baecfSMauro Carvalho Chehab 	struct dvb_frontend*		fe;
102786baecfSMauro Carvalho Chehab 
103786baecfSMauro Carvalho Chehab 	u16			pid[DMX_PES_OTHER];
104786baecfSMauro Carvalho Chehab 
105786baecfSMauro Carvalho Chehab 	/* USB bits */
106786baecfSMauro Carvalho Chehab 	struct usb_device		*udev;
107786baecfSMauro Carvalho Chehab 	u8				trans_count;
108786baecfSMauro Carvalho Chehab 	unsigned int			command_pipe;
109786baecfSMauro Carvalho Chehab 	unsigned int			result_pipe;
110786baecfSMauro Carvalho Chehab 	unsigned int			in_pipe;
111786baecfSMauro Carvalho Chehab 	unsigned int			out_pipe;
112786baecfSMauro Carvalho Chehab 	unsigned int			irq_pipe;
113786baecfSMauro Carvalho Chehab 	enum ttusb_dec_interface	interface;
114786baecfSMauro Carvalho Chehab 	struct mutex			usb_mutex;
115786baecfSMauro Carvalho Chehab 
116786baecfSMauro Carvalho Chehab 	void			*irq_buffer;
117786baecfSMauro Carvalho Chehab 	struct urb		*irq_urb;
118786baecfSMauro Carvalho Chehab 	dma_addr_t		irq_dma_handle;
119786baecfSMauro Carvalho Chehab 	void			*iso_buffer;
120786baecfSMauro Carvalho Chehab 	struct urb		*iso_urb[ISO_BUF_COUNT];
121786baecfSMauro Carvalho Chehab 	int			iso_stream_count;
122786baecfSMauro Carvalho Chehab 	struct mutex		iso_mutex;
123786baecfSMauro Carvalho Chehab 
124786baecfSMauro Carvalho Chehab 	u8				packet[MAX_PVA_LENGTH + 4];
125786baecfSMauro Carvalho Chehab 	enum ttusb_dec_packet_type	packet_type;
126786baecfSMauro Carvalho Chehab 	int				packet_state;
127786baecfSMauro Carvalho Chehab 	int				packet_length;
128786baecfSMauro Carvalho Chehab 	int				packet_payload_length;
129786baecfSMauro Carvalho Chehab 	u16				next_packet_id;
130786baecfSMauro Carvalho Chehab 
131786baecfSMauro Carvalho Chehab 	int				pva_stream_count;
132786baecfSMauro Carvalho Chehab 	int				filter_stream_count;
133786baecfSMauro Carvalho Chehab 
134786baecfSMauro Carvalho Chehab 	struct dvb_filter_pes2ts	a_pes2ts;
135786baecfSMauro Carvalho Chehab 	struct dvb_filter_pes2ts	v_pes2ts;
136786baecfSMauro Carvalho Chehab 
137786baecfSMauro Carvalho Chehab 	u8			v_pes[16 + MAX_PVA_LENGTH];
138786baecfSMauro Carvalho Chehab 	int			v_pes_length;
139786baecfSMauro Carvalho Chehab 	int			v_pes_postbytes;
140786baecfSMauro Carvalho Chehab 
141786baecfSMauro Carvalho Chehab 	struct list_head	urb_frame_list;
142786baecfSMauro Carvalho Chehab 	struct tasklet_struct	urb_tasklet;
143786baecfSMauro Carvalho Chehab 	spinlock_t		urb_frame_list_lock;
144786baecfSMauro Carvalho Chehab 
145786baecfSMauro Carvalho Chehab 	struct dvb_demux_filter	*audio_filter;
146786baecfSMauro Carvalho Chehab 	struct dvb_demux_filter	*video_filter;
147786baecfSMauro Carvalho Chehab 	struct list_head	filter_info_list;
148786baecfSMauro Carvalho Chehab 	spinlock_t		filter_info_list_lock;
149786baecfSMauro Carvalho Chehab 
150786baecfSMauro Carvalho Chehab 	struct input_dev	*rc_input_dev;
151786baecfSMauro Carvalho Chehab 	char			rc_phys[64];
152786baecfSMauro Carvalho Chehab 
153786baecfSMauro Carvalho Chehab 	int			active; /* Loaded successfully */
154786baecfSMauro Carvalho Chehab };
155786baecfSMauro Carvalho Chehab 
156786baecfSMauro Carvalho Chehab struct urb_frame {
157786baecfSMauro Carvalho Chehab 	u8			data[ISO_FRAME_SIZE];
158786baecfSMauro Carvalho Chehab 	int			length;
159786baecfSMauro Carvalho Chehab 	struct list_head	urb_frame_list;
160786baecfSMauro Carvalho Chehab };
161786baecfSMauro Carvalho Chehab 
162786baecfSMauro Carvalho Chehab struct filter_info {
163786baecfSMauro Carvalho Chehab 	u8			stream_id;
164786baecfSMauro Carvalho Chehab 	struct dvb_demux_filter	*filter;
165786baecfSMauro Carvalho Chehab 	struct list_head	filter_info_list;
166786baecfSMauro Carvalho Chehab };
167786baecfSMauro Carvalho Chehab 
168786baecfSMauro Carvalho Chehab static u16 rc_keys[] = {
169786baecfSMauro Carvalho Chehab 	KEY_POWER,
170786baecfSMauro Carvalho Chehab 	KEY_MUTE,
171786baecfSMauro Carvalho Chehab 	KEY_1,
172786baecfSMauro Carvalho Chehab 	KEY_2,
173786baecfSMauro Carvalho Chehab 	KEY_3,
174786baecfSMauro Carvalho Chehab 	KEY_4,
175786baecfSMauro Carvalho Chehab 	KEY_5,
176786baecfSMauro Carvalho Chehab 	KEY_6,
177786baecfSMauro Carvalho Chehab 	KEY_7,
178786baecfSMauro Carvalho Chehab 	KEY_8,
179786baecfSMauro Carvalho Chehab 	KEY_9,
180786baecfSMauro Carvalho Chehab 	KEY_0,
181786baecfSMauro Carvalho Chehab 	KEY_CHANNELUP,
182786baecfSMauro Carvalho Chehab 	KEY_VOLUMEDOWN,
183786baecfSMauro Carvalho Chehab 	KEY_OK,
184786baecfSMauro Carvalho Chehab 	KEY_VOLUMEUP,
185786baecfSMauro Carvalho Chehab 	KEY_CHANNELDOWN,
186786baecfSMauro Carvalho Chehab 	KEY_PREVIOUS,
187786baecfSMauro Carvalho Chehab 	KEY_ESC,
188786baecfSMauro Carvalho Chehab 	KEY_RED,
189786baecfSMauro Carvalho Chehab 	KEY_GREEN,
190786baecfSMauro Carvalho Chehab 	KEY_YELLOW,
191786baecfSMauro Carvalho Chehab 	KEY_BLUE,
192786baecfSMauro Carvalho Chehab 	KEY_OPTION,
193786baecfSMauro Carvalho Chehab 	KEY_M,
194786baecfSMauro Carvalho Chehab 	KEY_RADIO
195786baecfSMauro Carvalho Chehab };
196786baecfSMauro Carvalho Chehab 
dvb_filter_pes2ts_init(struct dvb_filter_pes2ts * p2ts,unsigned short pid,dvb_filter_pes2ts_cb_t * cb,void * priv)197b676e731SMauro Carvalho Chehab static void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts,
198b676e731SMauro Carvalho Chehab 				   unsigned short pid,
199b676e731SMauro Carvalho Chehab 				   dvb_filter_pes2ts_cb_t *cb, void *priv)
200b676e731SMauro Carvalho Chehab {
201b676e731SMauro Carvalho Chehab 	unsigned char *buf=p2ts->buf;
202b676e731SMauro Carvalho Chehab 
203b676e731SMauro Carvalho Chehab 	buf[0]=0x47;
204b676e731SMauro Carvalho Chehab 	buf[1]=(pid>>8);
205b676e731SMauro Carvalho Chehab 	buf[2]=pid&0xff;
206b676e731SMauro Carvalho Chehab 	p2ts->cc=0;
207b676e731SMauro Carvalho Chehab 	p2ts->cb=cb;
208b676e731SMauro Carvalho Chehab 	p2ts->priv=priv;
209b676e731SMauro Carvalho Chehab }
210b676e731SMauro Carvalho Chehab 
dvb_filter_pes2ts(struct dvb_filter_pes2ts * p2ts,unsigned char * pes,int len,int payload_start)211b676e731SMauro Carvalho Chehab static int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts,
212b676e731SMauro Carvalho Chehab 			     unsigned char *pes, int len, int payload_start)
213b676e731SMauro Carvalho Chehab {
214b676e731SMauro Carvalho Chehab 	unsigned char *buf=p2ts->buf;
215b676e731SMauro Carvalho Chehab 	int ret=0, rest;
216b676e731SMauro Carvalho Chehab 
217b676e731SMauro Carvalho Chehab 	//len=6+((pes[4]<<8)|pes[5]);
218b676e731SMauro Carvalho Chehab 
219b676e731SMauro Carvalho Chehab 	if (payload_start)
220b676e731SMauro Carvalho Chehab 		buf[1]|=0x40;
221b676e731SMauro Carvalho Chehab 	else
222b676e731SMauro Carvalho Chehab 		buf[1]&=~0x40;
223b676e731SMauro Carvalho Chehab 	while (len>=184) {
224b676e731SMauro Carvalho Chehab 		buf[3]=0x10|((p2ts->cc++)&0x0f);
225b676e731SMauro Carvalho Chehab 		memcpy(buf+4, pes, 184);
226b676e731SMauro Carvalho Chehab 		if ((ret=p2ts->cb(p2ts->priv, buf)))
227b676e731SMauro Carvalho Chehab 			return ret;
228b676e731SMauro Carvalho Chehab 		len-=184; pes+=184;
229b676e731SMauro Carvalho Chehab 		buf[1]&=~0x40;
230b676e731SMauro Carvalho Chehab 	}
231b676e731SMauro Carvalho Chehab 	if (!len)
232b676e731SMauro Carvalho Chehab 		return 0;
233b676e731SMauro Carvalho Chehab 	buf[3]=0x30|((p2ts->cc++)&0x0f);
234b676e731SMauro Carvalho Chehab 	rest=183-len;
235b676e731SMauro Carvalho Chehab 	if (rest) {
236b676e731SMauro Carvalho Chehab 		buf[5]=0x00;
237b676e731SMauro Carvalho Chehab 		if (rest-1)
238b676e731SMauro Carvalho Chehab 			memset(buf+6, 0xff, rest-1);
239b676e731SMauro Carvalho Chehab 	}
240b676e731SMauro Carvalho Chehab 	buf[4]=rest;
241b676e731SMauro Carvalho Chehab 	memcpy(buf+5+rest, pes, len);
242b676e731SMauro Carvalho Chehab 	return p2ts->cb(p2ts->priv, buf);
243b676e731SMauro Carvalho Chehab }
244b676e731SMauro Carvalho Chehab 
245786baecfSMauro Carvalho Chehab static void ttusb_dec_set_model(struct ttusb_dec *dec,
246786baecfSMauro Carvalho Chehab 				enum ttusb_dec_model model);
247786baecfSMauro Carvalho Chehab 
ttusb_dec_handle_irq(struct urb * urb)248786baecfSMauro Carvalho Chehab static void ttusb_dec_handle_irq( struct urb *urb)
249786baecfSMauro Carvalho Chehab {
250786baecfSMauro Carvalho Chehab 	struct ttusb_dec *dec = urb->context;
251786baecfSMauro Carvalho Chehab 	char *buffer = dec->irq_buffer;
252786baecfSMauro Carvalho Chehab 	int retval;
253f933d160SJia-Ju Bai 	int index = buffer[4];
254786baecfSMauro Carvalho Chehab 
255786baecfSMauro Carvalho Chehab 	switch(urb->status) {
256786baecfSMauro Carvalho Chehab 		case 0: /*success*/
257786baecfSMauro Carvalho Chehab 			break;
258786baecfSMauro Carvalho Chehab 		case -ECONNRESET:
259786baecfSMauro Carvalho Chehab 		case -ENOENT:
260786baecfSMauro Carvalho Chehab 		case -ESHUTDOWN:
261786baecfSMauro Carvalho Chehab 		case -ETIME:
262786baecfSMauro Carvalho Chehab 			/* this urb is dead, cleanup */
263786baecfSMauro Carvalho Chehab 			dprintk("%s:urb shutting down with status: %d\n",
264786baecfSMauro Carvalho Chehab 					__func__, urb->status);
265786baecfSMauro Carvalho Chehab 			return;
266786baecfSMauro Carvalho Chehab 		default:
267786baecfSMauro Carvalho Chehab 			dprintk("%s:nonzero status received: %d\n",
268786baecfSMauro Carvalho Chehab 					__func__,urb->status);
269786baecfSMauro Carvalho Chehab 			goto exit;
270786baecfSMauro Carvalho Chehab 	}
271786baecfSMauro Carvalho Chehab 
272786baecfSMauro Carvalho Chehab 	if ((buffer[0] == 0x1) && (buffer[2] == 0x15))  {
2733cc26912SMauro Carvalho Chehab 		/*
2743cc26912SMauro Carvalho Chehab 		 * IR - Event
2753cc26912SMauro Carvalho Chehab 		 *
2763cc26912SMauro Carvalho Chehab 		 * this is an fact a bit too simple implementation;
277786baecfSMauro Carvalho Chehab 		 * the box also reports a keyrepeat signal
2783e4d8f48SMauro Carvalho Chehab 		 * (with buffer[3] == 0x40) in an interval of ~100ms.
279786baecfSMauro Carvalho Chehab 		 * But to handle this correctly we had to imlemenent some
280786baecfSMauro Carvalho Chehab 		 * kind of timer which signals a 'key up' event if no
281786baecfSMauro Carvalho Chehab 		 * keyrepeat signal is received for lets say 200ms.
282786baecfSMauro Carvalho Chehab 		 * this should/could be added later ...
2833cc26912SMauro Carvalho Chehab 		 * for now lets report each signal as a key down and up
2843cc26912SMauro Carvalho Chehab 		 */
285f933d160SJia-Ju Bai 		if (index - 1 < ARRAY_SIZE(rc_keys)) {
286f933d160SJia-Ju Bai 			dprintk("%s:rc signal:%d\n", __func__, index);
287f933d160SJia-Ju Bai 			input_report_key(dec->rc_input_dev, rc_keys[index - 1], 1);
288786baecfSMauro Carvalho Chehab 			input_sync(dec->rc_input_dev);
289f933d160SJia-Ju Bai 			input_report_key(dec->rc_input_dev, rc_keys[index - 1], 0);
290786baecfSMauro Carvalho Chehab 			input_sync(dec->rc_input_dev);
291786baecfSMauro Carvalho Chehab 		}
2923cc26912SMauro Carvalho Chehab 	}
293786baecfSMauro Carvalho Chehab 
2943cc26912SMauro Carvalho Chehab exit:
2953cc26912SMauro Carvalho Chehab 	retval = usb_submit_urb(urb, GFP_ATOMIC);
296786baecfSMauro Carvalho Chehab 	if (retval)
297786baecfSMauro Carvalho Chehab 		printk("%s - usb_commit_urb failed with result: %d\n",
298786baecfSMauro Carvalho Chehab 			__func__, retval);
299786baecfSMauro Carvalho Chehab }
300786baecfSMauro Carvalho Chehab 
crc16(u16 crc,const u8 * buf,size_t len)301786baecfSMauro Carvalho Chehab static u16 crc16(u16 crc, const u8 *buf, size_t len)
302786baecfSMauro Carvalho Chehab {
303786baecfSMauro Carvalho Chehab 	u16 tmp;
304786baecfSMauro Carvalho Chehab 
305786baecfSMauro Carvalho Chehab 	while (len--) {
306786baecfSMauro Carvalho Chehab 		crc ^= *buf++;
307786baecfSMauro Carvalho Chehab 		crc ^= (u8)crc >> 4;
308786baecfSMauro Carvalho Chehab 		tmp = (u8)crc;
309786baecfSMauro Carvalho Chehab 		crc ^= (tmp ^ (tmp << 1)) << 4;
310786baecfSMauro Carvalho Chehab 	}
311786baecfSMauro Carvalho Chehab 	return crc;
312786baecfSMauro Carvalho Chehab }
313786baecfSMauro Carvalho Chehab 
ttusb_dec_send_command(struct ttusb_dec * dec,const u8 command,int param_length,const u8 params[],int * result_length,u8 cmd_result[])314786baecfSMauro Carvalho Chehab static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command,
315786baecfSMauro Carvalho Chehab 				  int param_length, const u8 params[],
316786baecfSMauro Carvalho Chehab 				  int *result_length, u8 cmd_result[])
317786baecfSMauro Carvalho Chehab {
31861fc8749SMauro Carvalho Chehab 	int result, actual_len;
319786baecfSMauro Carvalho Chehab 	u8 *b;
320786baecfSMauro Carvalho Chehab 
321786baecfSMauro Carvalho Chehab 	dprintk("%s\n", __func__);
322786baecfSMauro Carvalho Chehab 
323a10feaf8STomas Bortoli 	b = kzalloc(COMMAND_PACKET_SIZE + 4, GFP_KERNEL);
324786baecfSMauro Carvalho Chehab 	if (!b)
325786baecfSMauro Carvalho Chehab 		return -ENOMEM;
326786baecfSMauro Carvalho Chehab 
327dba328baSMauro Carvalho Chehab 	result = mutex_lock_interruptible(&dec->usb_mutex);
328dba328baSMauro Carvalho Chehab 	if (result) {
329786baecfSMauro Carvalho Chehab 		printk("%s: Failed to lock usb mutex.\n", __func__);
33036b9d695SEvgeny Novikov 		goto err_free;
331786baecfSMauro Carvalho Chehab 	}
332786baecfSMauro Carvalho Chehab 
333786baecfSMauro Carvalho Chehab 	b[0] = 0xaa;
334786baecfSMauro Carvalho Chehab 	b[1] = ++dec->trans_count;
335786baecfSMauro Carvalho Chehab 	b[2] = command;
336786baecfSMauro Carvalho Chehab 	b[3] = param_length;
337786baecfSMauro Carvalho Chehab 
338786baecfSMauro Carvalho Chehab 	if (params)
339786baecfSMauro Carvalho Chehab 		memcpy(&b[4], params, param_length);
340786baecfSMauro Carvalho Chehab 
341786baecfSMauro Carvalho Chehab 	if (debug) {
34261fc8749SMauro Carvalho Chehab 		printk(KERN_DEBUG "%s: command: %*ph\n",
34361fc8749SMauro Carvalho Chehab 		       __func__, param_length, b);
344786baecfSMauro Carvalho Chehab 	}
345786baecfSMauro Carvalho Chehab 
346786baecfSMauro Carvalho Chehab 	result = usb_bulk_msg(dec->udev, dec->command_pipe, b,
347786baecfSMauro Carvalho Chehab 			      COMMAND_PACKET_SIZE + 4, &actual_len, 1000);
348786baecfSMauro Carvalho Chehab 
349786baecfSMauro Carvalho Chehab 	if (result) {
350786baecfSMauro Carvalho Chehab 		printk("%s: command bulk message failed: error %d\n",
351786baecfSMauro Carvalho Chehab 		       __func__, result);
35236b9d695SEvgeny Novikov 		goto err_mutex_unlock;
353786baecfSMauro Carvalho Chehab 	}
354786baecfSMauro Carvalho Chehab 
355786baecfSMauro Carvalho Chehab 	result = usb_bulk_msg(dec->udev, dec->result_pipe, b,
356786baecfSMauro Carvalho Chehab 			      COMMAND_PACKET_SIZE + 4, &actual_len, 1000);
357786baecfSMauro Carvalho Chehab 
358786baecfSMauro Carvalho Chehab 	if (result) {
359786baecfSMauro Carvalho Chehab 		printk("%s: result bulk message failed: error %d\n",
360786baecfSMauro Carvalho Chehab 		       __func__, result);
36136b9d695SEvgeny Novikov 		goto err_mutex_unlock;
362786baecfSMauro Carvalho Chehab 	} else {
363786baecfSMauro Carvalho Chehab 		if (debug) {
36461fc8749SMauro Carvalho Chehab 			printk(KERN_DEBUG "%s: result: %*ph\n",
36561fc8749SMauro Carvalho Chehab 			       __func__, actual_len, b);
366786baecfSMauro Carvalho Chehab 		}
367786baecfSMauro Carvalho Chehab 
368786baecfSMauro Carvalho Chehab 		if (result_length)
369786baecfSMauro Carvalho Chehab 			*result_length = b[3];
370786baecfSMauro Carvalho Chehab 		if (cmd_result && b[3] > 0)
371786baecfSMauro Carvalho Chehab 			memcpy(cmd_result, &b[4], b[3]);
372dba328baSMauro Carvalho Chehab 	}
373786baecfSMauro Carvalho Chehab 
37436b9d695SEvgeny Novikov err_mutex_unlock:
375786baecfSMauro Carvalho Chehab 	mutex_unlock(&dec->usb_mutex);
37636b9d695SEvgeny Novikov err_free:
377786baecfSMauro Carvalho Chehab 	kfree(b);
378dba328baSMauro Carvalho Chehab 	return result;
379786baecfSMauro Carvalho Chehab }
380786baecfSMauro Carvalho Chehab 
ttusb_dec_get_stb_state(struct ttusb_dec * dec,unsigned int * mode,unsigned int * model,unsigned int * version)381786baecfSMauro Carvalho Chehab static int ttusb_dec_get_stb_state (struct ttusb_dec *dec, unsigned int *mode,
382786baecfSMauro Carvalho Chehab 				    unsigned int *model, unsigned int *version)
383786baecfSMauro Carvalho Chehab {
384786baecfSMauro Carvalho Chehab 	u8 c[COMMAND_PACKET_SIZE];
385786baecfSMauro Carvalho Chehab 	int c_length;
386786baecfSMauro Carvalho Chehab 	int result;
387786baecfSMauro Carvalho Chehab 	__be32 tmp;
388786baecfSMauro Carvalho Chehab 
389786baecfSMauro Carvalho Chehab 	dprintk("%s\n", __func__);
390786baecfSMauro Carvalho Chehab 
391786baecfSMauro Carvalho Chehab 	result = ttusb_dec_send_command(dec, 0x08, 0, NULL, &c_length, c);
392786baecfSMauro Carvalho Chehab 	if (result)
393786baecfSMauro Carvalho Chehab 		return result;
394786baecfSMauro Carvalho Chehab 
395786baecfSMauro Carvalho Chehab 	if (c_length >= 0x0c) {
396786baecfSMauro Carvalho Chehab 		if (mode != NULL) {
397786baecfSMauro Carvalho Chehab 			memcpy(&tmp, c, 4);
398786baecfSMauro Carvalho Chehab 			*mode = ntohl(tmp);
399786baecfSMauro Carvalho Chehab 		}
400786baecfSMauro Carvalho Chehab 		if (model != NULL) {
401786baecfSMauro Carvalho Chehab 			memcpy(&tmp, &c[4], 4);
402786baecfSMauro Carvalho Chehab 			*model = ntohl(tmp);
403786baecfSMauro Carvalho Chehab 		}
404786baecfSMauro Carvalho Chehab 		if (version != NULL) {
405786baecfSMauro Carvalho Chehab 			memcpy(&tmp, &c[8], 4);
406786baecfSMauro Carvalho Chehab 			*version = ntohl(tmp);
407786baecfSMauro Carvalho Chehab 		}
408786baecfSMauro Carvalho Chehab 		return 0;
409786baecfSMauro Carvalho Chehab 	} else {
410cf732b5fSAlexey Khoroshilov 		return -ENOENT;
411786baecfSMauro Carvalho Chehab 	}
412786baecfSMauro Carvalho Chehab }
413786baecfSMauro Carvalho Chehab 
ttusb_dec_audio_pes2ts_cb(void * priv,unsigned char * data)414786baecfSMauro Carvalho Chehab static int ttusb_dec_audio_pes2ts_cb(void *priv, unsigned char *data)
415786baecfSMauro Carvalho Chehab {
416786baecfSMauro Carvalho Chehab 	struct ttusb_dec *dec = priv;
417786baecfSMauro Carvalho Chehab 
418786baecfSMauro Carvalho Chehab 	dec->audio_filter->feed->cb.ts(data, 188, NULL, 0,
419fdbeb962SMauro Carvalho Chehab 				       &dec->audio_filter->feed->feed.ts, NULL);
420786baecfSMauro Carvalho Chehab 
421786baecfSMauro Carvalho Chehab 	return 0;
422786baecfSMauro Carvalho Chehab }
423786baecfSMauro Carvalho Chehab 
ttusb_dec_video_pes2ts_cb(void * priv,unsigned char * data)424786baecfSMauro Carvalho Chehab static int ttusb_dec_video_pes2ts_cb(void *priv, unsigned char *data)
425786baecfSMauro Carvalho Chehab {
426786baecfSMauro Carvalho Chehab 	struct ttusb_dec *dec = priv;
427786baecfSMauro Carvalho Chehab 
428786baecfSMauro Carvalho Chehab 	dec->video_filter->feed->cb.ts(data, 188, NULL, 0,
429fdbeb962SMauro Carvalho Chehab 				       &dec->video_filter->feed->feed.ts, NULL);
430786baecfSMauro Carvalho Chehab 
431786baecfSMauro Carvalho Chehab 	return 0;
432786baecfSMauro Carvalho Chehab }
433786baecfSMauro Carvalho Chehab 
ttusb_dec_set_pids(struct ttusb_dec * dec)434786baecfSMauro Carvalho Chehab static void ttusb_dec_set_pids(struct ttusb_dec *dec)
435786baecfSMauro Carvalho Chehab {
436786baecfSMauro Carvalho Chehab 	u8 b[] = { 0x00, 0x00, 0x00, 0x00,
437786baecfSMauro Carvalho Chehab 		   0x00, 0x00, 0xff, 0xff,
438786baecfSMauro Carvalho Chehab 		   0xff, 0xff, 0xff, 0xff };
439786baecfSMauro Carvalho Chehab 
440786baecfSMauro Carvalho Chehab 	__be16 pcr = htons(dec->pid[DMX_PES_PCR]);
441786baecfSMauro Carvalho Chehab 	__be16 audio = htons(dec->pid[DMX_PES_AUDIO]);
442786baecfSMauro Carvalho Chehab 	__be16 video = htons(dec->pid[DMX_PES_VIDEO]);
443786baecfSMauro Carvalho Chehab 
444786baecfSMauro Carvalho Chehab 	dprintk("%s\n", __func__);
445786baecfSMauro Carvalho Chehab 
446786baecfSMauro Carvalho Chehab 	memcpy(&b[0], &pcr, 2);
447786baecfSMauro Carvalho Chehab 	memcpy(&b[2], &audio, 2);
448786baecfSMauro Carvalho Chehab 	memcpy(&b[4], &video, 2);
449786baecfSMauro Carvalho Chehab 
450786baecfSMauro Carvalho Chehab 	ttusb_dec_send_command(dec, 0x50, sizeof(b), b, NULL, NULL);
451786baecfSMauro Carvalho Chehab 
452786baecfSMauro Carvalho Chehab 	dvb_filter_pes2ts_init(&dec->a_pes2ts, dec->pid[DMX_PES_AUDIO],
453786baecfSMauro Carvalho Chehab 			       ttusb_dec_audio_pes2ts_cb, dec);
454786baecfSMauro Carvalho Chehab 	dvb_filter_pes2ts_init(&dec->v_pes2ts, dec->pid[DMX_PES_VIDEO],
455786baecfSMauro Carvalho Chehab 			       ttusb_dec_video_pes2ts_cb, dec);
456786baecfSMauro Carvalho Chehab 	dec->v_pes_length = 0;
457786baecfSMauro Carvalho Chehab 	dec->v_pes_postbytes = 0;
458786baecfSMauro Carvalho Chehab }
459786baecfSMauro Carvalho Chehab 
ttusb_dec_process_pva(struct ttusb_dec * dec,u8 * pva,int length)460786baecfSMauro Carvalho Chehab static void ttusb_dec_process_pva(struct ttusb_dec *dec, u8 *pva, int length)
461786baecfSMauro Carvalho Chehab {
462786baecfSMauro Carvalho Chehab 	if (length < 8) {
463786baecfSMauro Carvalho Chehab 		printk("%s: packet too short - discarding\n", __func__);
464786baecfSMauro Carvalho Chehab 		return;
465786baecfSMauro Carvalho Chehab 	}
466786baecfSMauro Carvalho Chehab 
467786baecfSMauro Carvalho Chehab 	if (length > 8 + MAX_PVA_LENGTH) {
468786baecfSMauro Carvalho Chehab 		printk("%s: packet too long - discarding\n", __func__);
469786baecfSMauro Carvalho Chehab 		return;
470786baecfSMauro Carvalho Chehab 	}
471786baecfSMauro Carvalho Chehab 
472786baecfSMauro Carvalho Chehab 	switch (pva[2]) {
473786baecfSMauro Carvalho Chehab 
474786baecfSMauro Carvalho Chehab 	case 0x01: {		/* VideoStream */
475786baecfSMauro Carvalho Chehab 		int prebytes = pva[5] & 0x03;
476786baecfSMauro Carvalho Chehab 		int postbytes = (pva[5] & 0x0c) >> 2;
477786baecfSMauro Carvalho Chehab 		__be16 v_pes_payload_length;
478786baecfSMauro Carvalho Chehab 
479786baecfSMauro Carvalho Chehab 		if (output_pva) {
480786baecfSMauro Carvalho Chehab 			dec->video_filter->feed->cb.ts(pva, length, NULL, 0,
481fdbeb962SMauro Carvalho Chehab 				&dec->video_filter->feed->feed.ts, NULL);
482786baecfSMauro Carvalho Chehab 			return;
483786baecfSMauro Carvalho Chehab 		}
484786baecfSMauro Carvalho Chehab 
485786baecfSMauro Carvalho Chehab 		if (dec->v_pes_postbytes > 0 &&
486786baecfSMauro Carvalho Chehab 		    dec->v_pes_postbytes == prebytes) {
487786baecfSMauro Carvalho Chehab 			memcpy(&dec->v_pes[dec->v_pes_length],
488786baecfSMauro Carvalho Chehab 			       &pva[12], prebytes);
489786baecfSMauro Carvalho Chehab 
490786baecfSMauro Carvalho Chehab 			dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes,
491786baecfSMauro Carvalho Chehab 					  dec->v_pes_length + prebytes, 1);
492786baecfSMauro Carvalho Chehab 		}
493786baecfSMauro Carvalho Chehab 
494786baecfSMauro Carvalho Chehab 		if (pva[5] & 0x10) {
495786baecfSMauro Carvalho Chehab 			dec->v_pes[7] = 0x80;
496786baecfSMauro Carvalho Chehab 			dec->v_pes[8] = 0x05;
497786baecfSMauro Carvalho Chehab 
498786baecfSMauro Carvalho Chehab 			dec->v_pes[9] = 0x21 | ((pva[8] & 0xc0) >> 5);
499786baecfSMauro Carvalho Chehab 			dec->v_pes[10] = ((pva[8] & 0x3f) << 2) |
500786baecfSMauro Carvalho Chehab 					 ((pva[9] & 0xc0) >> 6);
501786baecfSMauro Carvalho Chehab 			dec->v_pes[11] = 0x01 |
502786baecfSMauro Carvalho Chehab 					 ((pva[9] & 0x3f) << 2) |
503786baecfSMauro Carvalho Chehab 					 ((pva[10] & 0x80) >> 6);
504786baecfSMauro Carvalho Chehab 			dec->v_pes[12] = ((pva[10] & 0x7f) << 1) |
505786baecfSMauro Carvalho Chehab 					 ((pva[11] & 0xc0) >> 7);
506786baecfSMauro Carvalho Chehab 			dec->v_pes[13] = 0x01 | ((pva[11] & 0x7f) << 1);
507786baecfSMauro Carvalho Chehab 
508786baecfSMauro Carvalho Chehab 			memcpy(&dec->v_pes[14], &pva[12 + prebytes],
509786baecfSMauro Carvalho Chehab 			       length - 12 - prebytes);
510786baecfSMauro Carvalho Chehab 			dec->v_pes_length = 14 + length - 12 - prebytes;
511786baecfSMauro Carvalho Chehab 		} else {
512786baecfSMauro Carvalho Chehab 			dec->v_pes[7] = 0x00;
513786baecfSMauro Carvalho Chehab 			dec->v_pes[8] = 0x00;
514786baecfSMauro Carvalho Chehab 
515786baecfSMauro Carvalho Chehab 			memcpy(&dec->v_pes[9], &pva[8], length - 8);
516786baecfSMauro Carvalho Chehab 			dec->v_pes_length = 9 + length - 8;
517786baecfSMauro Carvalho Chehab 		}
518786baecfSMauro Carvalho Chehab 
519786baecfSMauro Carvalho Chehab 		dec->v_pes_postbytes = postbytes;
520786baecfSMauro Carvalho Chehab 
521786baecfSMauro Carvalho Chehab 		if (dec->v_pes[9 + dec->v_pes[8]] == 0x00 &&
522786baecfSMauro Carvalho Chehab 		    dec->v_pes[10 + dec->v_pes[8]] == 0x00 &&
523786baecfSMauro Carvalho Chehab 		    dec->v_pes[11 + dec->v_pes[8]] == 0x01)
524786baecfSMauro Carvalho Chehab 			dec->v_pes[6] = 0x84;
525786baecfSMauro Carvalho Chehab 		else
526786baecfSMauro Carvalho Chehab 			dec->v_pes[6] = 0x80;
527786baecfSMauro Carvalho Chehab 
528786baecfSMauro Carvalho Chehab 		v_pes_payload_length = htons(dec->v_pes_length - 6 +
529786baecfSMauro Carvalho Chehab 					     postbytes);
530786baecfSMauro Carvalho Chehab 		memcpy(&dec->v_pes[4], &v_pes_payload_length, 2);
531786baecfSMauro Carvalho Chehab 
532786baecfSMauro Carvalho Chehab 		if (postbytes == 0)
533786baecfSMauro Carvalho Chehab 			dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes,
534786baecfSMauro Carvalho Chehab 					  dec->v_pes_length, 1);
535786baecfSMauro Carvalho Chehab 
536786baecfSMauro Carvalho Chehab 		break;
537786baecfSMauro Carvalho Chehab 	}
538786baecfSMauro Carvalho Chehab 
539786baecfSMauro Carvalho Chehab 	case 0x02:		/* MainAudioStream */
540786baecfSMauro Carvalho Chehab 		if (output_pva) {
541786baecfSMauro Carvalho Chehab 			dec->audio_filter->feed->cb.ts(pva, length, NULL, 0,
542fdbeb962SMauro Carvalho Chehab 				&dec->audio_filter->feed->feed.ts, NULL);
543786baecfSMauro Carvalho Chehab 			return;
544786baecfSMauro Carvalho Chehab 		}
545786baecfSMauro Carvalho Chehab 
546786baecfSMauro Carvalho Chehab 		dvb_filter_pes2ts(&dec->a_pes2ts, &pva[8], length - 8,
547786baecfSMauro Carvalho Chehab 				  pva[5] & 0x10);
548786baecfSMauro Carvalho Chehab 		break;
549786baecfSMauro Carvalho Chehab 
550786baecfSMauro Carvalho Chehab 	default:
551786baecfSMauro Carvalho Chehab 		printk("%s: unknown PVA type: %02x.\n", __func__,
552786baecfSMauro Carvalho Chehab 		       pva[2]);
553786baecfSMauro Carvalho Chehab 		break;
554786baecfSMauro Carvalho Chehab 	}
555786baecfSMauro Carvalho Chehab }
556786baecfSMauro Carvalho Chehab 
ttusb_dec_process_filter(struct ttusb_dec * dec,u8 * packet,int length)557786baecfSMauro Carvalho Chehab static void ttusb_dec_process_filter(struct ttusb_dec *dec, u8 *packet,
558786baecfSMauro Carvalho Chehab 				     int length)
559786baecfSMauro Carvalho Chehab {
560786baecfSMauro Carvalho Chehab 	struct list_head *item;
561786baecfSMauro Carvalho Chehab 	struct filter_info *finfo;
562786baecfSMauro Carvalho Chehab 	struct dvb_demux_filter *filter = NULL;
563786baecfSMauro Carvalho Chehab 	unsigned long flags;
564786baecfSMauro Carvalho Chehab 	u8 sid;
565786baecfSMauro Carvalho Chehab 
566786baecfSMauro Carvalho Chehab 	sid = packet[1];
567786baecfSMauro Carvalho Chehab 	spin_lock_irqsave(&dec->filter_info_list_lock, flags);
568786baecfSMauro Carvalho Chehab 	for (item = dec->filter_info_list.next; item != &dec->filter_info_list;
569786baecfSMauro Carvalho Chehab 	     item = item->next) {
570786baecfSMauro Carvalho Chehab 		finfo = list_entry(item, struct filter_info, filter_info_list);
571786baecfSMauro Carvalho Chehab 		if (finfo->stream_id == sid) {
572786baecfSMauro Carvalho Chehab 			filter = finfo->filter;
573786baecfSMauro Carvalho Chehab 			break;
574786baecfSMauro Carvalho Chehab 		}
575786baecfSMauro Carvalho Chehab 	}
576786baecfSMauro Carvalho Chehab 	spin_unlock_irqrestore(&dec->filter_info_list_lock, flags);
577786baecfSMauro Carvalho Chehab 
578786baecfSMauro Carvalho Chehab 	if (filter)
579786baecfSMauro Carvalho Chehab 		filter->feed->cb.sec(&packet[2], length - 2, NULL, 0,
580fdbeb962SMauro Carvalho Chehab 				     &filter->filter, NULL);
581786baecfSMauro Carvalho Chehab }
582786baecfSMauro Carvalho Chehab 
ttusb_dec_process_packet(struct ttusb_dec * dec)583786baecfSMauro Carvalho Chehab static void ttusb_dec_process_packet(struct ttusb_dec *dec)
584786baecfSMauro Carvalho Chehab {
585786baecfSMauro Carvalho Chehab 	int i;
586786baecfSMauro Carvalho Chehab 	u16 csum = 0;
587786baecfSMauro Carvalho Chehab 	u16 packet_id;
588786baecfSMauro Carvalho Chehab 
589786baecfSMauro Carvalho Chehab 	if (dec->packet_length % 2) {
590786baecfSMauro Carvalho Chehab 		printk("%s: odd sized packet - discarding\n", __func__);
591786baecfSMauro Carvalho Chehab 		return;
592786baecfSMauro Carvalho Chehab 	}
593786baecfSMauro Carvalho Chehab 
594786baecfSMauro Carvalho Chehab 	for (i = 0; i < dec->packet_length; i += 2)
595786baecfSMauro Carvalho Chehab 		csum ^= ((dec->packet[i] << 8) + dec->packet[i + 1]);
596786baecfSMauro Carvalho Chehab 
597786baecfSMauro Carvalho Chehab 	if (csum) {
598786baecfSMauro Carvalho Chehab 		printk("%s: checksum failed - discarding\n", __func__);
599786baecfSMauro Carvalho Chehab 		return;
600786baecfSMauro Carvalho Chehab 	}
601786baecfSMauro Carvalho Chehab 
602786baecfSMauro Carvalho Chehab 	packet_id = dec->packet[dec->packet_length - 4] << 8;
603786baecfSMauro Carvalho Chehab 	packet_id += dec->packet[dec->packet_length - 3];
604786baecfSMauro Carvalho Chehab 
605786baecfSMauro Carvalho Chehab 	if ((packet_id != dec->next_packet_id) && dec->next_packet_id) {
606786baecfSMauro Carvalho Chehab 		printk("%s: warning: lost packets between %u and %u\n",
607786baecfSMauro Carvalho Chehab 		       __func__, dec->next_packet_id - 1, packet_id);
608786baecfSMauro Carvalho Chehab 	}
609786baecfSMauro Carvalho Chehab 
610786baecfSMauro Carvalho Chehab 	if (packet_id == 0xffff)
611786baecfSMauro Carvalho Chehab 		dec->next_packet_id = 0x8000;
612786baecfSMauro Carvalho Chehab 	else
613786baecfSMauro Carvalho Chehab 		dec->next_packet_id = packet_id + 1;
614786baecfSMauro Carvalho Chehab 
615786baecfSMauro Carvalho Chehab 	switch (dec->packet_type) {
616786baecfSMauro Carvalho Chehab 	case TTUSB_DEC_PACKET_PVA:
617786baecfSMauro Carvalho Chehab 		if (dec->pva_stream_count)
618786baecfSMauro Carvalho Chehab 			ttusb_dec_process_pva(dec, dec->packet,
619786baecfSMauro Carvalho Chehab 					      dec->packet_payload_length);
620786baecfSMauro Carvalho Chehab 		break;
621786baecfSMauro Carvalho Chehab 
622786baecfSMauro Carvalho Chehab 	case TTUSB_DEC_PACKET_SECTION:
623786baecfSMauro Carvalho Chehab 		if (dec->filter_stream_count)
624786baecfSMauro Carvalho Chehab 			ttusb_dec_process_filter(dec, dec->packet,
625786baecfSMauro Carvalho Chehab 						 dec->packet_payload_length);
626786baecfSMauro Carvalho Chehab 		break;
627786baecfSMauro Carvalho Chehab 
628786baecfSMauro Carvalho Chehab 	case TTUSB_DEC_PACKET_EMPTY:
629786baecfSMauro Carvalho Chehab 		break;
630786baecfSMauro Carvalho Chehab 	}
631786baecfSMauro Carvalho Chehab }
632786baecfSMauro Carvalho Chehab 
swap_bytes(u8 * b,int length)633786baecfSMauro Carvalho Chehab static void swap_bytes(u8 *b, int length)
634786baecfSMauro Carvalho Chehab {
635786baecfSMauro Carvalho Chehab 	length -= length % 2;
63641cc14baSFabian Frederick 	for (; length; b += 2, length -= 2)
63741cc14baSFabian Frederick 		swap(*b, *(b + 1));
638786baecfSMauro Carvalho Chehab }
639786baecfSMauro Carvalho Chehab 
ttusb_dec_process_urb_frame(struct ttusb_dec * dec,u8 * b,int length)640786baecfSMauro Carvalho Chehab static void ttusb_dec_process_urb_frame(struct ttusb_dec *dec, u8 *b,
641786baecfSMauro Carvalho Chehab 					int length)
642786baecfSMauro Carvalho Chehab {
643786baecfSMauro Carvalho Chehab 	swap_bytes(b, length);
644786baecfSMauro Carvalho Chehab 
645786baecfSMauro Carvalho Chehab 	while (length) {
646786baecfSMauro Carvalho Chehab 		switch (dec->packet_state) {
647786baecfSMauro Carvalho Chehab 
648786baecfSMauro Carvalho Chehab 		case 0:
649786baecfSMauro Carvalho Chehab 		case 1:
650786baecfSMauro Carvalho Chehab 		case 2:
651786baecfSMauro Carvalho Chehab 			if (*b++ == 0xaa)
652786baecfSMauro Carvalho Chehab 				dec->packet_state++;
653786baecfSMauro Carvalho Chehab 			else
654786baecfSMauro Carvalho Chehab 				dec->packet_state = 0;
655786baecfSMauro Carvalho Chehab 
656786baecfSMauro Carvalho Chehab 			length--;
657786baecfSMauro Carvalho Chehab 			break;
658786baecfSMauro Carvalho Chehab 
659786baecfSMauro Carvalho Chehab 		case 3:
660786baecfSMauro Carvalho Chehab 			if (*b == 0x00) {
661786baecfSMauro Carvalho Chehab 				dec->packet_state++;
662786baecfSMauro Carvalho Chehab 				dec->packet_length = 0;
663786baecfSMauro Carvalho Chehab 			} else if (*b != 0xaa) {
664786baecfSMauro Carvalho Chehab 				dec->packet_state = 0;
665786baecfSMauro Carvalho Chehab 			}
666786baecfSMauro Carvalho Chehab 
667786baecfSMauro Carvalho Chehab 			b++;
668786baecfSMauro Carvalho Chehab 			length--;
669786baecfSMauro Carvalho Chehab 			break;
670786baecfSMauro Carvalho Chehab 
671786baecfSMauro Carvalho Chehab 		case 4:
672786baecfSMauro Carvalho Chehab 			dec->packet[dec->packet_length++] = *b++;
673786baecfSMauro Carvalho Chehab 
674786baecfSMauro Carvalho Chehab 			if (dec->packet_length == 2) {
675786baecfSMauro Carvalho Chehab 				if (dec->packet[0] == 'A' &&
676786baecfSMauro Carvalho Chehab 				    dec->packet[1] == 'V') {
677786baecfSMauro Carvalho Chehab 					dec->packet_type =
678786baecfSMauro Carvalho Chehab 						TTUSB_DEC_PACKET_PVA;
679786baecfSMauro Carvalho Chehab 					dec->packet_state++;
680786baecfSMauro Carvalho Chehab 				} else if (dec->packet[0] == 'S') {
681786baecfSMauro Carvalho Chehab 					dec->packet_type =
682786baecfSMauro Carvalho Chehab 						TTUSB_DEC_PACKET_SECTION;
683786baecfSMauro Carvalho Chehab 					dec->packet_state++;
684786baecfSMauro Carvalho Chehab 				} else if (dec->packet[0] == 0x00) {
685786baecfSMauro Carvalho Chehab 					dec->packet_type =
686786baecfSMauro Carvalho Chehab 						TTUSB_DEC_PACKET_EMPTY;
687786baecfSMauro Carvalho Chehab 					dec->packet_payload_length = 2;
688786baecfSMauro Carvalho Chehab 					dec->packet_state = 7;
689786baecfSMauro Carvalho Chehab 				} else {
690bf769a4eSMauro Carvalho Chehab 					printk("%s: unknown packet type: %02x%02x\n",
691bf769a4eSMauro Carvalho Chehab 					       __func__,
692786baecfSMauro Carvalho Chehab 					       dec->packet[0], dec->packet[1]);
693786baecfSMauro Carvalho Chehab 					dec->packet_state = 0;
694786baecfSMauro Carvalho Chehab 				}
695786baecfSMauro Carvalho Chehab 			}
696786baecfSMauro Carvalho Chehab 
697786baecfSMauro Carvalho Chehab 			length--;
698786baecfSMauro Carvalho Chehab 			break;
699786baecfSMauro Carvalho Chehab 
700786baecfSMauro Carvalho Chehab 		case 5:
701786baecfSMauro Carvalho Chehab 			dec->packet[dec->packet_length++] = *b++;
702786baecfSMauro Carvalho Chehab 
703786baecfSMauro Carvalho Chehab 			if (dec->packet_type == TTUSB_DEC_PACKET_PVA &&
704786baecfSMauro Carvalho Chehab 			    dec->packet_length == 8) {
705786baecfSMauro Carvalho Chehab 				dec->packet_state++;
706786baecfSMauro Carvalho Chehab 				dec->packet_payload_length = 8 +
707786baecfSMauro Carvalho Chehab 					(dec->packet[6] << 8) +
708786baecfSMauro Carvalho Chehab 					dec->packet[7];
709786baecfSMauro Carvalho Chehab 			} else if (dec->packet_type ==
710786baecfSMauro Carvalho Chehab 					TTUSB_DEC_PACKET_SECTION &&
711786baecfSMauro Carvalho Chehab 				   dec->packet_length == 5) {
712786baecfSMauro Carvalho Chehab 				dec->packet_state++;
713786baecfSMauro Carvalho Chehab 				dec->packet_payload_length = 5 +
714786baecfSMauro Carvalho Chehab 					((dec->packet[3] & 0x0f) << 8) +
715786baecfSMauro Carvalho Chehab 					dec->packet[4];
716786baecfSMauro Carvalho Chehab 			}
717786baecfSMauro Carvalho Chehab 
718786baecfSMauro Carvalho Chehab 			length--;
719786baecfSMauro Carvalho Chehab 			break;
720786baecfSMauro Carvalho Chehab 
721786baecfSMauro Carvalho Chehab 		case 6: {
722786baecfSMauro Carvalho Chehab 			int remainder = dec->packet_payload_length -
723786baecfSMauro Carvalho Chehab 					dec->packet_length;
724786baecfSMauro Carvalho Chehab 
725786baecfSMauro Carvalho Chehab 			if (length >= remainder) {
726786baecfSMauro Carvalho Chehab 				memcpy(dec->packet + dec->packet_length,
727786baecfSMauro Carvalho Chehab 				       b, remainder);
728786baecfSMauro Carvalho Chehab 				dec->packet_length += remainder;
729786baecfSMauro Carvalho Chehab 				b += remainder;
730786baecfSMauro Carvalho Chehab 				length -= remainder;
731786baecfSMauro Carvalho Chehab 				dec->packet_state++;
732786baecfSMauro Carvalho Chehab 			} else {
733786baecfSMauro Carvalho Chehab 				memcpy(&dec->packet[dec->packet_length],
734786baecfSMauro Carvalho Chehab 				       b, length);
735786baecfSMauro Carvalho Chehab 				dec->packet_length += length;
736786baecfSMauro Carvalho Chehab 				length = 0;
737786baecfSMauro Carvalho Chehab 			}
738786baecfSMauro Carvalho Chehab 
739786baecfSMauro Carvalho Chehab 			break;
740786baecfSMauro Carvalho Chehab 		}
741786baecfSMauro Carvalho Chehab 
742786baecfSMauro Carvalho Chehab 		case 7: {
743786baecfSMauro Carvalho Chehab 			int tail = 4;
744786baecfSMauro Carvalho Chehab 
745786baecfSMauro Carvalho Chehab 			dec->packet[dec->packet_length++] = *b++;
746786baecfSMauro Carvalho Chehab 
747786baecfSMauro Carvalho Chehab 			if (dec->packet_type == TTUSB_DEC_PACKET_SECTION &&
748786baecfSMauro Carvalho Chehab 			    dec->packet_payload_length % 2)
749786baecfSMauro Carvalho Chehab 				tail++;
750786baecfSMauro Carvalho Chehab 
751786baecfSMauro Carvalho Chehab 			if (dec->packet_length ==
752786baecfSMauro Carvalho Chehab 			    dec->packet_payload_length + tail) {
753786baecfSMauro Carvalho Chehab 				ttusb_dec_process_packet(dec);
754786baecfSMauro Carvalho Chehab 				dec->packet_state = 0;
755786baecfSMauro Carvalho Chehab 			}
756786baecfSMauro Carvalho Chehab 
757786baecfSMauro Carvalho Chehab 			length--;
758786baecfSMauro Carvalho Chehab 			break;
759786baecfSMauro Carvalho Chehab 		}
760786baecfSMauro Carvalho Chehab 
761786baecfSMauro Carvalho Chehab 		default:
762786baecfSMauro Carvalho Chehab 			printk("%s: illegal packet state encountered.\n",
763786baecfSMauro Carvalho Chehab 			       __func__);
764786baecfSMauro Carvalho Chehab 			dec->packet_state = 0;
765786baecfSMauro Carvalho Chehab 		}
766786baecfSMauro Carvalho Chehab 	}
767786baecfSMauro Carvalho Chehab }
768786baecfSMauro Carvalho Chehab 
ttusb_dec_process_urb_frame_list(struct tasklet_struct * t)769f3b60b06SAllen Pais static void ttusb_dec_process_urb_frame_list(struct tasklet_struct *t)
770786baecfSMauro Carvalho Chehab {
771f3b60b06SAllen Pais 	struct ttusb_dec *dec = from_tasklet(dec, t, urb_tasklet);
772786baecfSMauro Carvalho Chehab 	struct list_head *item;
773786baecfSMauro Carvalho Chehab 	struct urb_frame *frame;
774786baecfSMauro Carvalho Chehab 	unsigned long flags;
775786baecfSMauro Carvalho Chehab 
776786baecfSMauro Carvalho Chehab 	while (1) {
777786baecfSMauro Carvalho Chehab 		spin_lock_irqsave(&dec->urb_frame_list_lock, flags);
778786baecfSMauro Carvalho Chehab 		if ((item = dec->urb_frame_list.next) != &dec->urb_frame_list) {
779786baecfSMauro Carvalho Chehab 			frame = list_entry(item, struct urb_frame,
780786baecfSMauro Carvalho Chehab 					   urb_frame_list);
781786baecfSMauro Carvalho Chehab 			list_del(&frame->urb_frame_list);
782786baecfSMauro Carvalho Chehab 		} else {
783786baecfSMauro Carvalho Chehab 			spin_unlock_irqrestore(&dec->urb_frame_list_lock,
784786baecfSMauro Carvalho Chehab 					       flags);
785786baecfSMauro Carvalho Chehab 			return;
786786baecfSMauro Carvalho Chehab 		}
787786baecfSMauro Carvalho Chehab 		spin_unlock_irqrestore(&dec->urb_frame_list_lock, flags);
788786baecfSMauro Carvalho Chehab 
789786baecfSMauro Carvalho Chehab 		ttusb_dec_process_urb_frame(dec, frame->data, frame->length);
790786baecfSMauro Carvalho Chehab 		kfree(frame);
791786baecfSMauro Carvalho Chehab 	}
792786baecfSMauro Carvalho Chehab }
793786baecfSMauro Carvalho Chehab 
ttusb_dec_process_urb(struct urb * urb)794786baecfSMauro Carvalho Chehab static void ttusb_dec_process_urb(struct urb *urb)
795786baecfSMauro Carvalho Chehab {
796786baecfSMauro Carvalho Chehab 	struct ttusb_dec *dec = urb->context;
797786baecfSMauro Carvalho Chehab 
798786baecfSMauro Carvalho Chehab 	if (!urb->status) {
799786baecfSMauro Carvalho Chehab 		int i;
800786baecfSMauro Carvalho Chehab 
801786baecfSMauro Carvalho Chehab 		for (i = 0; i < FRAMES_PER_ISO_BUF; i++) {
802786baecfSMauro Carvalho Chehab 			struct usb_iso_packet_descriptor *d;
803786baecfSMauro Carvalho Chehab 			u8 *b;
804786baecfSMauro Carvalho Chehab 			int length;
805786baecfSMauro Carvalho Chehab 			struct urb_frame *frame;
806786baecfSMauro Carvalho Chehab 
807786baecfSMauro Carvalho Chehab 			d = &urb->iso_frame_desc[i];
808786baecfSMauro Carvalho Chehab 			b = urb->transfer_buffer + d->offset;
809786baecfSMauro Carvalho Chehab 			length = d->actual_length;
810786baecfSMauro Carvalho Chehab 
811786baecfSMauro Carvalho Chehab 			if ((frame = kmalloc(sizeof(struct urb_frame),
812786baecfSMauro Carvalho Chehab 					     GFP_ATOMIC))) {
813786baecfSMauro Carvalho Chehab 				unsigned long flags;
814786baecfSMauro Carvalho Chehab 
815786baecfSMauro Carvalho Chehab 				memcpy(frame->data, b, length);
816786baecfSMauro Carvalho Chehab 				frame->length = length;
817786baecfSMauro Carvalho Chehab 
818786baecfSMauro Carvalho Chehab 				spin_lock_irqsave(&dec->urb_frame_list_lock,
819786baecfSMauro Carvalho Chehab 						     flags);
820786baecfSMauro Carvalho Chehab 				list_add_tail(&frame->urb_frame_list,
821786baecfSMauro Carvalho Chehab 					      &dec->urb_frame_list);
822786baecfSMauro Carvalho Chehab 				spin_unlock_irqrestore(&dec->urb_frame_list_lock,
823786baecfSMauro Carvalho Chehab 						       flags);
824786baecfSMauro Carvalho Chehab 
825786baecfSMauro Carvalho Chehab 				tasklet_schedule(&dec->urb_tasklet);
826786baecfSMauro Carvalho Chehab 			}
827786baecfSMauro Carvalho Chehab 		}
828786baecfSMauro Carvalho Chehab 	} else {
829786baecfSMauro Carvalho Chehab 		 /* -ENOENT is expected when unlinking urbs */
830786baecfSMauro Carvalho Chehab 		if (urb->status != -ENOENT)
831786baecfSMauro Carvalho Chehab 			dprintk("%s: urb error: %d\n", __func__,
832786baecfSMauro Carvalho Chehab 				urb->status);
833786baecfSMauro Carvalho Chehab 	}
834786baecfSMauro Carvalho Chehab 
835786baecfSMauro Carvalho Chehab 	if (dec->iso_stream_count)
836786baecfSMauro Carvalho Chehab 		usb_submit_urb(urb, GFP_ATOMIC);
837786baecfSMauro Carvalho Chehab }
838786baecfSMauro Carvalho Chehab 
ttusb_dec_setup_urbs(struct ttusb_dec * dec)839786baecfSMauro Carvalho Chehab static void ttusb_dec_setup_urbs(struct ttusb_dec *dec)
840786baecfSMauro Carvalho Chehab {
841786baecfSMauro Carvalho Chehab 	int i, j, buffer_offset = 0;
842786baecfSMauro Carvalho Chehab 
843786baecfSMauro Carvalho Chehab 	dprintk("%s\n", __func__);
844786baecfSMauro Carvalho Chehab 
845786baecfSMauro Carvalho Chehab 	for (i = 0; i < ISO_BUF_COUNT; i++) {
846786baecfSMauro Carvalho Chehab 		int frame_offset = 0;
847786baecfSMauro Carvalho Chehab 		struct urb *urb = dec->iso_urb[i];
848786baecfSMauro Carvalho Chehab 
849786baecfSMauro Carvalho Chehab 		urb->dev = dec->udev;
850786baecfSMauro Carvalho Chehab 		urb->context = dec;
851786baecfSMauro Carvalho Chehab 		urb->complete = ttusb_dec_process_urb;
852786baecfSMauro Carvalho Chehab 		urb->pipe = dec->in_pipe;
853786baecfSMauro Carvalho Chehab 		urb->transfer_flags = URB_ISO_ASAP;
854786baecfSMauro Carvalho Chehab 		urb->interval = 1;
855786baecfSMauro Carvalho Chehab 		urb->number_of_packets = FRAMES_PER_ISO_BUF;
856786baecfSMauro Carvalho Chehab 		urb->transfer_buffer_length = ISO_FRAME_SIZE *
857786baecfSMauro Carvalho Chehab 					      FRAMES_PER_ISO_BUF;
858786baecfSMauro Carvalho Chehab 		urb->transfer_buffer = dec->iso_buffer + buffer_offset;
859786baecfSMauro Carvalho Chehab 		buffer_offset += ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF;
860786baecfSMauro Carvalho Chehab 
861786baecfSMauro Carvalho Chehab 		for (j = 0; j < FRAMES_PER_ISO_BUF; j++) {
862786baecfSMauro Carvalho Chehab 			urb->iso_frame_desc[j].offset = frame_offset;
863786baecfSMauro Carvalho Chehab 			urb->iso_frame_desc[j].length = ISO_FRAME_SIZE;
864786baecfSMauro Carvalho Chehab 			frame_offset += ISO_FRAME_SIZE;
865786baecfSMauro Carvalho Chehab 		}
866786baecfSMauro Carvalho Chehab 	}
867786baecfSMauro Carvalho Chehab }
868786baecfSMauro Carvalho Chehab 
ttusb_dec_stop_iso_xfer(struct ttusb_dec * dec)869786baecfSMauro Carvalho Chehab static void ttusb_dec_stop_iso_xfer(struct ttusb_dec *dec)
870786baecfSMauro Carvalho Chehab {
871786baecfSMauro Carvalho Chehab 	int i;
872786baecfSMauro Carvalho Chehab 
873786baecfSMauro Carvalho Chehab 	dprintk("%s\n", __func__);
874786baecfSMauro Carvalho Chehab 
875786baecfSMauro Carvalho Chehab 	if (mutex_lock_interruptible(&dec->iso_mutex))
876786baecfSMauro Carvalho Chehab 		return;
877786baecfSMauro Carvalho Chehab 
878786baecfSMauro Carvalho Chehab 	dec->iso_stream_count--;
879786baecfSMauro Carvalho Chehab 
880786baecfSMauro Carvalho Chehab 	if (!dec->iso_stream_count) {
881786baecfSMauro Carvalho Chehab 		for (i = 0; i < ISO_BUF_COUNT; i++)
882786baecfSMauro Carvalho Chehab 			usb_kill_urb(dec->iso_urb[i]);
883786baecfSMauro Carvalho Chehab 	}
884786baecfSMauro Carvalho Chehab 
885786baecfSMauro Carvalho Chehab 	mutex_unlock(&dec->iso_mutex);
886786baecfSMauro Carvalho Chehab }
887786baecfSMauro Carvalho Chehab 
888786baecfSMauro Carvalho Chehab /* Setting the interface of the DEC tends to take down the USB communications
889786baecfSMauro Carvalho Chehab  * for a short period, so it's important not to call this function just before
890786baecfSMauro Carvalho Chehab  * trying to talk to it.
891786baecfSMauro Carvalho Chehab  */
ttusb_dec_set_interface(struct ttusb_dec * dec,enum ttusb_dec_interface interface)892786baecfSMauro Carvalho Chehab static int ttusb_dec_set_interface(struct ttusb_dec *dec,
893786baecfSMauro Carvalho Chehab 				   enum ttusb_dec_interface interface)
894786baecfSMauro Carvalho Chehab {
895786baecfSMauro Carvalho Chehab 	int result = 0;
896786baecfSMauro Carvalho Chehab 	u8 b[] = { 0x05 };
897786baecfSMauro Carvalho Chehab 
898786baecfSMauro Carvalho Chehab 	if (interface != dec->interface) {
899786baecfSMauro Carvalho Chehab 		switch (interface) {
900786baecfSMauro Carvalho Chehab 		case TTUSB_DEC_INTERFACE_INITIAL:
901786baecfSMauro Carvalho Chehab 			result = usb_set_interface(dec->udev, 0, 0);
902786baecfSMauro Carvalho Chehab 			break;
903786baecfSMauro Carvalho Chehab 		case TTUSB_DEC_INTERFACE_IN:
904786baecfSMauro Carvalho Chehab 			result = ttusb_dec_send_command(dec, 0x80, sizeof(b),
905786baecfSMauro Carvalho Chehab 							b, NULL, NULL);
906786baecfSMauro Carvalho Chehab 			if (result)
907786baecfSMauro Carvalho Chehab 				return result;
908786baecfSMauro Carvalho Chehab 			result = usb_set_interface(dec->udev, 0, 8);
909786baecfSMauro Carvalho Chehab 			break;
910786baecfSMauro Carvalho Chehab 		case TTUSB_DEC_INTERFACE_OUT:
911786baecfSMauro Carvalho Chehab 			result = usb_set_interface(dec->udev, 0, 1);
912786baecfSMauro Carvalho Chehab 			break;
913786baecfSMauro Carvalho Chehab 		}
914786baecfSMauro Carvalho Chehab 
915786baecfSMauro Carvalho Chehab 		if (result)
916786baecfSMauro Carvalho Chehab 			return result;
917786baecfSMauro Carvalho Chehab 
918786baecfSMauro Carvalho Chehab 		dec->interface = interface;
919786baecfSMauro Carvalho Chehab 	}
920786baecfSMauro Carvalho Chehab 
921786baecfSMauro Carvalho Chehab 	return 0;
922786baecfSMauro Carvalho Chehab }
923786baecfSMauro Carvalho Chehab 
ttusb_dec_start_iso_xfer(struct ttusb_dec * dec)924786baecfSMauro Carvalho Chehab static int ttusb_dec_start_iso_xfer(struct ttusb_dec *dec)
925786baecfSMauro Carvalho Chehab {
926786baecfSMauro Carvalho Chehab 	int i, result;
927786baecfSMauro Carvalho Chehab 
928786baecfSMauro Carvalho Chehab 	dprintk("%s\n", __func__);
929786baecfSMauro Carvalho Chehab 
930786baecfSMauro Carvalho Chehab 	if (mutex_lock_interruptible(&dec->iso_mutex))
931786baecfSMauro Carvalho Chehab 		return -EAGAIN;
932786baecfSMauro Carvalho Chehab 
933786baecfSMauro Carvalho Chehab 	if (!dec->iso_stream_count) {
934786baecfSMauro Carvalho Chehab 		ttusb_dec_setup_urbs(dec);
935786baecfSMauro Carvalho Chehab 
936786baecfSMauro Carvalho Chehab 		dec->packet_state = 0;
937786baecfSMauro Carvalho Chehab 		dec->v_pes_postbytes = 0;
938786baecfSMauro Carvalho Chehab 		dec->next_packet_id = 0;
939786baecfSMauro Carvalho Chehab 
940786baecfSMauro Carvalho Chehab 		for (i = 0; i < ISO_BUF_COUNT; i++) {
941786baecfSMauro Carvalho Chehab 			if ((result = usb_submit_urb(dec->iso_urb[i],
942786baecfSMauro Carvalho Chehab 						     GFP_ATOMIC))) {
943bf769a4eSMauro Carvalho Chehab 				printk("%s: failed urb submission %d: error %d\n",
944bf769a4eSMauro Carvalho Chehab 				       __func__, i, result);
945786baecfSMauro Carvalho Chehab 
946786baecfSMauro Carvalho Chehab 				while (i) {
947786baecfSMauro Carvalho Chehab 					usb_kill_urb(dec->iso_urb[i - 1]);
948786baecfSMauro Carvalho Chehab 					i--;
949786baecfSMauro Carvalho Chehab 				}
950786baecfSMauro Carvalho Chehab 
951786baecfSMauro Carvalho Chehab 				mutex_unlock(&dec->iso_mutex);
952786baecfSMauro Carvalho Chehab 				return result;
953786baecfSMauro Carvalho Chehab 			}
954786baecfSMauro Carvalho Chehab 		}
955786baecfSMauro Carvalho Chehab 	}
956786baecfSMauro Carvalho Chehab 
957786baecfSMauro Carvalho Chehab 	dec->iso_stream_count++;
958786baecfSMauro Carvalho Chehab 
959786baecfSMauro Carvalho Chehab 	mutex_unlock(&dec->iso_mutex);
960786baecfSMauro Carvalho Chehab 
961786baecfSMauro Carvalho Chehab 	return 0;
962786baecfSMauro Carvalho Chehab }
963786baecfSMauro Carvalho Chehab 
ttusb_dec_start_ts_feed(struct dvb_demux_feed * dvbdmxfeed)964786baecfSMauro Carvalho Chehab static int ttusb_dec_start_ts_feed(struct dvb_demux_feed *dvbdmxfeed)
965786baecfSMauro Carvalho Chehab {
966786baecfSMauro Carvalho Chehab 	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
967786baecfSMauro Carvalho Chehab 	struct ttusb_dec *dec = dvbdmx->priv;
968786baecfSMauro Carvalho Chehab 	u8 b0[] = { 0x05 };
969786baecfSMauro Carvalho Chehab 	int result = 0;
970786baecfSMauro Carvalho Chehab 
971786baecfSMauro Carvalho Chehab 	dprintk("%s\n", __func__);
972786baecfSMauro Carvalho Chehab 
973786baecfSMauro Carvalho Chehab 	dprintk("  ts_type:");
974786baecfSMauro Carvalho Chehab 
975786baecfSMauro Carvalho Chehab 	if (dvbdmxfeed->ts_type & TS_DECODER)
976786baecfSMauro Carvalho Chehab 		dprintk(" TS_DECODER");
977786baecfSMauro Carvalho Chehab 
978786baecfSMauro Carvalho Chehab 	if (dvbdmxfeed->ts_type & TS_PACKET)
979786baecfSMauro Carvalho Chehab 		dprintk(" TS_PACKET");
980786baecfSMauro Carvalho Chehab 
981786baecfSMauro Carvalho Chehab 	if (dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY)
982786baecfSMauro Carvalho Chehab 		dprintk(" TS_PAYLOAD_ONLY");
983786baecfSMauro Carvalho Chehab 
984786baecfSMauro Carvalho Chehab 	dprintk("\n");
985786baecfSMauro Carvalho Chehab 
986786baecfSMauro Carvalho Chehab 	switch (dvbdmxfeed->pes_type) {
987786baecfSMauro Carvalho Chehab 
988fde04ab9SMauro Carvalho Chehab 	case DMX_PES_VIDEO:
989fde04ab9SMauro Carvalho Chehab 		dprintk("  pes_type: DMX_PES_VIDEO\n");
990786baecfSMauro Carvalho Chehab 		dec->pid[DMX_PES_PCR] = dvbdmxfeed->pid;
991786baecfSMauro Carvalho Chehab 		dec->pid[DMX_PES_VIDEO] = dvbdmxfeed->pid;
992786baecfSMauro Carvalho Chehab 		dec->video_filter = dvbdmxfeed->filter;
993786baecfSMauro Carvalho Chehab 		ttusb_dec_set_pids(dec);
994786baecfSMauro Carvalho Chehab 		break;
995786baecfSMauro Carvalho Chehab 
996fde04ab9SMauro Carvalho Chehab 	case DMX_PES_AUDIO:
997fde04ab9SMauro Carvalho Chehab 		dprintk("  pes_type: DMX_PES_AUDIO\n");
998786baecfSMauro Carvalho Chehab 		dec->pid[DMX_PES_AUDIO] = dvbdmxfeed->pid;
999786baecfSMauro Carvalho Chehab 		dec->audio_filter = dvbdmxfeed->filter;
1000786baecfSMauro Carvalho Chehab 		ttusb_dec_set_pids(dec);
1001786baecfSMauro Carvalho Chehab 		break;
1002786baecfSMauro Carvalho Chehab 
1003fde04ab9SMauro Carvalho Chehab 	case DMX_PES_TELETEXT:
1004786baecfSMauro Carvalho Chehab 		dec->pid[DMX_PES_TELETEXT] = dvbdmxfeed->pid;
1005fde04ab9SMauro Carvalho Chehab 		dprintk("  pes_type: DMX_PES_TELETEXT(not supported)\n");
1006786baecfSMauro Carvalho Chehab 		return -ENOSYS;
1007786baecfSMauro Carvalho Chehab 
1008fde04ab9SMauro Carvalho Chehab 	case DMX_PES_PCR:
1009fde04ab9SMauro Carvalho Chehab 		dprintk("  pes_type: DMX_PES_PCR\n");
1010786baecfSMauro Carvalho Chehab 		dec->pid[DMX_PES_PCR] = dvbdmxfeed->pid;
1011786baecfSMauro Carvalho Chehab 		ttusb_dec_set_pids(dec);
1012786baecfSMauro Carvalho Chehab 		break;
1013786baecfSMauro Carvalho Chehab 
1014fde04ab9SMauro Carvalho Chehab 	case DMX_PES_OTHER:
1015fde04ab9SMauro Carvalho Chehab 		dprintk("  pes_type: DMX_PES_OTHER(not supported)\n");
1016786baecfSMauro Carvalho Chehab 		return -ENOSYS;
1017786baecfSMauro Carvalho Chehab 
1018786baecfSMauro Carvalho Chehab 	default:
1019786baecfSMauro Carvalho Chehab 		dprintk("  pes_type: unknown (%d)\n", dvbdmxfeed->pes_type);
1020786baecfSMauro Carvalho Chehab 		return -EINVAL;
1021786baecfSMauro Carvalho Chehab 
1022786baecfSMauro Carvalho Chehab 	}
1023786baecfSMauro Carvalho Chehab 
1024786baecfSMauro Carvalho Chehab 	result = ttusb_dec_send_command(dec, 0x80, sizeof(b0), b0, NULL, NULL);
1025786baecfSMauro Carvalho Chehab 	if (result)
1026786baecfSMauro Carvalho Chehab 		return result;
1027786baecfSMauro Carvalho Chehab 
1028786baecfSMauro Carvalho Chehab 	dec->pva_stream_count++;
1029786baecfSMauro Carvalho Chehab 	return ttusb_dec_start_iso_xfer(dec);
1030786baecfSMauro Carvalho Chehab }
1031786baecfSMauro Carvalho Chehab 
ttusb_dec_start_sec_feed(struct dvb_demux_feed * dvbdmxfeed)1032786baecfSMauro Carvalho Chehab static int ttusb_dec_start_sec_feed(struct dvb_demux_feed *dvbdmxfeed)
1033786baecfSMauro Carvalho Chehab {
1034786baecfSMauro Carvalho Chehab 	struct ttusb_dec *dec = dvbdmxfeed->demux->priv;
1035786baecfSMauro Carvalho Chehab 	u8 b0[] = { 0x00, 0x00, 0x00, 0x01,
1036786baecfSMauro Carvalho Chehab 		    0x00, 0x00, 0x00, 0x00,
1037786baecfSMauro Carvalho Chehab 		    0x00, 0x00, 0x00, 0x00,
1038786baecfSMauro Carvalho Chehab 		    0x00, 0x00, 0x00, 0x00,
1039786baecfSMauro Carvalho Chehab 		    0x00, 0xff, 0x00, 0x00,
1040786baecfSMauro Carvalho Chehab 		    0x00, 0x00, 0x00, 0x00,
1041786baecfSMauro Carvalho Chehab 		    0x00, 0x00, 0x00, 0x00,
1042786baecfSMauro Carvalho Chehab 		    0x00 };
1043786baecfSMauro Carvalho Chehab 	__be16 pid;
1044786baecfSMauro Carvalho Chehab 	u8 c[COMMAND_PACKET_SIZE];
1045786baecfSMauro Carvalho Chehab 	int c_length;
1046786baecfSMauro Carvalho Chehab 	int result;
1047786baecfSMauro Carvalho Chehab 	struct filter_info *finfo;
1048786baecfSMauro Carvalho Chehab 	unsigned long flags;
1049786baecfSMauro Carvalho Chehab 	u8 x = 1;
1050786baecfSMauro Carvalho Chehab 
1051786baecfSMauro Carvalho Chehab 	dprintk("%s\n", __func__);
1052786baecfSMauro Carvalho Chehab 
1053786baecfSMauro Carvalho Chehab 	pid = htons(dvbdmxfeed->pid);
1054786baecfSMauro Carvalho Chehab 	memcpy(&b0[0], &pid, 2);
1055786baecfSMauro Carvalho Chehab 	memcpy(&b0[4], &x, 1);
1056786baecfSMauro Carvalho Chehab 	memcpy(&b0[5], &dvbdmxfeed->filter->filter.filter_value[0], 1);
1057786baecfSMauro Carvalho Chehab 
1058786baecfSMauro Carvalho Chehab 	result = ttusb_dec_send_command(dec, 0x60, sizeof(b0), b0,
1059786baecfSMauro Carvalho Chehab 					&c_length, c);
1060786baecfSMauro Carvalho Chehab 
1061786baecfSMauro Carvalho Chehab 	if (!result) {
1062786baecfSMauro Carvalho Chehab 		if (c_length == 2) {
1063786baecfSMauro Carvalho Chehab 			if (!(finfo = kmalloc(sizeof(struct filter_info),
1064786baecfSMauro Carvalho Chehab 					      GFP_ATOMIC)))
1065786baecfSMauro Carvalho Chehab 				return -ENOMEM;
1066786baecfSMauro Carvalho Chehab 
1067786baecfSMauro Carvalho Chehab 			finfo->stream_id = c[1];
1068786baecfSMauro Carvalho Chehab 			finfo->filter = dvbdmxfeed->filter;
1069786baecfSMauro Carvalho Chehab 
1070786baecfSMauro Carvalho Chehab 			spin_lock_irqsave(&dec->filter_info_list_lock, flags);
1071786baecfSMauro Carvalho Chehab 			list_add_tail(&finfo->filter_info_list,
1072786baecfSMauro Carvalho Chehab 				      &dec->filter_info_list);
1073786baecfSMauro Carvalho Chehab 			spin_unlock_irqrestore(&dec->filter_info_list_lock,
1074786baecfSMauro Carvalho Chehab 					       flags);
1075786baecfSMauro Carvalho Chehab 
1076786baecfSMauro Carvalho Chehab 			dvbdmxfeed->priv = finfo;
1077786baecfSMauro Carvalho Chehab 
1078786baecfSMauro Carvalho Chehab 			dec->filter_stream_count++;
1079786baecfSMauro Carvalho Chehab 			return ttusb_dec_start_iso_xfer(dec);
1080786baecfSMauro Carvalho Chehab 		}
1081786baecfSMauro Carvalho Chehab 
1082786baecfSMauro Carvalho Chehab 		return -EAGAIN;
1083786baecfSMauro Carvalho Chehab 	} else
1084786baecfSMauro Carvalho Chehab 		return result;
1085786baecfSMauro Carvalho Chehab }
1086786baecfSMauro Carvalho Chehab 
ttusb_dec_start_feed(struct dvb_demux_feed * dvbdmxfeed)1087786baecfSMauro Carvalho Chehab static int ttusb_dec_start_feed(struct dvb_demux_feed *dvbdmxfeed)
1088786baecfSMauro Carvalho Chehab {
1089786baecfSMauro Carvalho Chehab 	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
1090786baecfSMauro Carvalho Chehab 
1091786baecfSMauro Carvalho Chehab 	dprintk("%s\n", __func__);
1092786baecfSMauro Carvalho Chehab 
1093786baecfSMauro Carvalho Chehab 	if (!dvbdmx->dmx.frontend)
1094786baecfSMauro Carvalho Chehab 		return -EINVAL;
1095786baecfSMauro Carvalho Chehab 
1096786baecfSMauro Carvalho Chehab 	dprintk("  pid: 0x%04X\n", dvbdmxfeed->pid);
1097786baecfSMauro Carvalho Chehab 
1098786baecfSMauro Carvalho Chehab 	switch (dvbdmxfeed->type) {
1099786baecfSMauro Carvalho Chehab 
1100786baecfSMauro Carvalho Chehab 	case DMX_TYPE_TS:
1101786baecfSMauro Carvalho Chehab 		return ttusb_dec_start_ts_feed(dvbdmxfeed);
1102786baecfSMauro Carvalho Chehab 
1103786baecfSMauro Carvalho Chehab 	case DMX_TYPE_SEC:
1104786baecfSMauro Carvalho Chehab 		return ttusb_dec_start_sec_feed(dvbdmxfeed);
1105786baecfSMauro Carvalho Chehab 
1106786baecfSMauro Carvalho Chehab 	default:
1107786baecfSMauro Carvalho Chehab 		dprintk("  type: unknown (%d)\n", dvbdmxfeed->type);
1108786baecfSMauro Carvalho Chehab 		return -EINVAL;
1109786baecfSMauro Carvalho Chehab 
1110786baecfSMauro Carvalho Chehab 	}
1111786baecfSMauro Carvalho Chehab }
1112786baecfSMauro Carvalho Chehab 
ttusb_dec_stop_ts_feed(struct dvb_demux_feed * dvbdmxfeed)1113786baecfSMauro Carvalho Chehab static int ttusb_dec_stop_ts_feed(struct dvb_demux_feed *dvbdmxfeed)
1114786baecfSMauro Carvalho Chehab {
1115786baecfSMauro Carvalho Chehab 	struct ttusb_dec *dec = dvbdmxfeed->demux->priv;
1116786baecfSMauro Carvalho Chehab 	u8 b0[] = { 0x00 };
1117786baecfSMauro Carvalho Chehab 
1118786baecfSMauro Carvalho Chehab 	ttusb_dec_send_command(dec, 0x81, sizeof(b0), b0, NULL, NULL);
1119786baecfSMauro Carvalho Chehab 
1120786baecfSMauro Carvalho Chehab 	dec->pva_stream_count--;
1121786baecfSMauro Carvalho Chehab 
1122786baecfSMauro Carvalho Chehab 	ttusb_dec_stop_iso_xfer(dec);
1123786baecfSMauro Carvalho Chehab 
1124786baecfSMauro Carvalho Chehab 	return 0;
1125786baecfSMauro Carvalho Chehab }
1126786baecfSMauro Carvalho Chehab 
ttusb_dec_stop_sec_feed(struct dvb_demux_feed * dvbdmxfeed)1127786baecfSMauro Carvalho Chehab static int ttusb_dec_stop_sec_feed(struct dvb_demux_feed *dvbdmxfeed)
1128786baecfSMauro Carvalho Chehab {
1129786baecfSMauro Carvalho Chehab 	struct ttusb_dec *dec = dvbdmxfeed->demux->priv;
1130786baecfSMauro Carvalho Chehab 	u8 b0[] = { 0x00, 0x00 };
1131*eff540dfSSu Hui 	struct filter_info *finfo = dvbdmxfeed->priv;
1132786baecfSMauro Carvalho Chehab 	unsigned long flags;
1133786baecfSMauro Carvalho Chehab 
1134786baecfSMauro Carvalho Chehab 	b0[1] = finfo->stream_id;
1135786baecfSMauro Carvalho Chehab 	spin_lock_irqsave(&dec->filter_info_list_lock, flags);
1136786baecfSMauro Carvalho Chehab 	list_del(&finfo->filter_info_list);
1137786baecfSMauro Carvalho Chehab 	spin_unlock_irqrestore(&dec->filter_info_list_lock, flags);
1138786baecfSMauro Carvalho Chehab 	kfree(finfo);
1139786baecfSMauro Carvalho Chehab 	ttusb_dec_send_command(dec, 0x62, sizeof(b0), b0, NULL, NULL);
1140786baecfSMauro Carvalho Chehab 
1141786baecfSMauro Carvalho Chehab 	dec->filter_stream_count--;
1142786baecfSMauro Carvalho Chehab 
1143786baecfSMauro Carvalho Chehab 	ttusb_dec_stop_iso_xfer(dec);
1144786baecfSMauro Carvalho Chehab 
1145786baecfSMauro Carvalho Chehab 	return 0;
1146786baecfSMauro Carvalho Chehab }
1147786baecfSMauro Carvalho Chehab 
ttusb_dec_stop_feed(struct dvb_demux_feed * dvbdmxfeed)1148786baecfSMauro Carvalho Chehab static int ttusb_dec_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
1149786baecfSMauro Carvalho Chehab {
1150786baecfSMauro Carvalho Chehab 	dprintk("%s\n", __func__);
1151786baecfSMauro Carvalho Chehab 
1152786baecfSMauro Carvalho Chehab 	switch (dvbdmxfeed->type) {
1153786baecfSMauro Carvalho Chehab 	case DMX_TYPE_TS:
1154786baecfSMauro Carvalho Chehab 		return ttusb_dec_stop_ts_feed(dvbdmxfeed);
1155786baecfSMauro Carvalho Chehab 
1156786baecfSMauro Carvalho Chehab 	case DMX_TYPE_SEC:
1157786baecfSMauro Carvalho Chehab 		return ttusb_dec_stop_sec_feed(dvbdmxfeed);
1158786baecfSMauro Carvalho Chehab 	}
1159786baecfSMauro Carvalho Chehab 
1160786baecfSMauro Carvalho Chehab 	return 0;
1161786baecfSMauro Carvalho Chehab }
1162786baecfSMauro Carvalho Chehab 
ttusb_dec_free_iso_urbs(struct ttusb_dec * dec)1163786baecfSMauro Carvalho Chehab static void ttusb_dec_free_iso_urbs(struct ttusb_dec *dec)
1164786baecfSMauro Carvalho Chehab {
1165786baecfSMauro Carvalho Chehab 	int i;
1166786baecfSMauro Carvalho Chehab 
1167786baecfSMauro Carvalho Chehab 	dprintk("%s\n", __func__);
1168786baecfSMauro Carvalho Chehab 
1169786baecfSMauro Carvalho Chehab 	for (i = 0; i < ISO_BUF_COUNT; i++)
1170786baecfSMauro Carvalho Chehab 		usb_free_urb(dec->iso_urb[i]);
11718d669f93SChristoph Hellwig 	kfree(dec->iso_buffer);
1172786baecfSMauro Carvalho Chehab }
1173786baecfSMauro Carvalho Chehab 
ttusb_dec_alloc_iso_urbs(struct ttusb_dec * dec)1174786baecfSMauro Carvalho Chehab static int ttusb_dec_alloc_iso_urbs(struct ttusb_dec *dec)
1175786baecfSMauro Carvalho Chehab {
1176786baecfSMauro Carvalho Chehab 	int i;
1177786baecfSMauro Carvalho Chehab 
1178786baecfSMauro Carvalho Chehab 	dprintk("%s\n", __func__);
1179786baecfSMauro Carvalho Chehab 
11808d669f93SChristoph Hellwig 	dec->iso_buffer = kcalloc(FRAMES_PER_ISO_BUF * ISO_BUF_COUNT,
11818d669f93SChristoph Hellwig 			ISO_FRAME_SIZE, GFP_KERNEL);
11828d669f93SChristoph Hellwig 	if (!dec->iso_buffer)
1183786baecfSMauro Carvalho Chehab 		return -ENOMEM;
1184786baecfSMauro Carvalho Chehab 
1185786baecfSMauro Carvalho Chehab 	for (i = 0; i < ISO_BUF_COUNT; i++) {
1186786baecfSMauro Carvalho Chehab 		struct urb *urb;
1187786baecfSMauro Carvalho Chehab 
1188786baecfSMauro Carvalho Chehab 		if (!(urb = usb_alloc_urb(FRAMES_PER_ISO_BUF, GFP_ATOMIC))) {
1189786baecfSMauro Carvalho Chehab 			ttusb_dec_free_iso_urbs(dec);
1190786baecfSMauro Carvalho Chehab 			return -ENOMEM;
1191786baecfSMauro Carvalho Chehab 		}
1192786baecfSMauro Carvalho Chehab 
1193786baecfSMauro Carvalho Chehab 		dec->iso_urb[i] = urb;
1194786baecfSMauro Carvalho Chehab 	}
1195786baecfSMauro Carvalho Chehab 
1196786baecfSMauro Carvalho Chehab 	ttusb_dec_setup_urbs(dec);
1197786baecfSMauro Carvalho Chehab 
1198786baecfSMauro Carvalho Chehab 	return 0;
1199786baecfSMauro Carvalho Chehab }
1200786baecfSMauro Carvalho Chehab 
ttusb_dec_init_tasklet(struct ttusb_dec * dec)1201786baecfSMauro Carvalho Chehab static void ttusb_dec_init_tasklet(struct ttusb_dec *dec)
1202786baecfSMauro Carvalho Chehab {
1203786baecfSMauro Carvalho Chehab 	spin_lock_init(&dec->urb_frame_list_lock);
1204786baecfSMauro Carvalho Chehab 	INIT_LIST_HEAD(&dec->urb_frame_list);
1205f3b60b06SAllen Pais 	tasklet_setup(&dec->urb_tasklet, ttusb_dec_process_urb_frame_list);
1206786baecfSMauro Carvalho Chehab }
1207786baecfSMauro Carvalho Chehab 
ttusb_init_rc(struct ttusb_dec * dec)1208786baecfSMauro Carvalho Chehab static int ttusb_init_rc( struct ttusb_dec *dec)
1209786baecfSMauro Carvalho Chehab {
1210786baecfSMauro Carvalho Chehab 	struct input_dev *input_dev;
1211786baecfSMauro Carvalho Chehab 	u8 b[] = { 0x00, 0x01 };
1212786baecfSMauro Carvalho Chehab 	int i;
1213786baecfSMauro Carvalho Chehab 	int err;
1214786baecfSMauro Carvalho Chehab 
1215786baecfSMauro Carvalho Chehab 	usb_make_path(dec->udev, dec->rc_phys, sizeof(dec->rc_phys));
1216786baecfSMauro Carvalho Chehab 	strlcat(dec->rc_phys, "/input0", sizeof(dec->rc_phys));
1217786baecfSMauro Carvalho Chehab 
1218786baecfSMauro Carvalho Chehab 	input_dev = input_allocate_device();
1219786baecfSMauro Carvalho Chehab 	if (!input_dev)
1220786baecfSMauro Carvalho Chehab 		return -ENOMEM;
1221786baecfSMauro Carvalho Chehab 
1222786baecfSMauro Carvalho Chehab 	input_dev->name = "ttusb_dec remote control";
1223786baecfSMauro Carvalho Chehab 	input_dev->phys = dec->rc_phys;
1224786baecfSMauro Carvalho Chehab 	input_dev->evbit[0] = BIT_MASK(EV_KEY);
1225786baecfSMauro Carvalho Chehab 	input_dev->keycodesize = sizeof(u16);
1226786baecfSMauro Carvalho Chehab 	input_dev->keycodemax = 0x1a;
1227786baecfSMauro Carvalho Chehab 	input_dev->keycode = rc_keys;
1228786baecfSMauro Carvalho Chehab 
1229786baecfSMauro Carvalho Chehab 	for (i = 0; i < ARRAY_SIZE(rc_keys); i++)
1230786baecfSMauro Carvalho Chehab 		  set_bit(rc_keys[i], input_dev->keybit);
1231786baecfSMauro Carvalho Chehab 
1232786baecfSMauro Carvalho Chehab 	err = input_register_device(input_dev);
1233786baecfSMauro Carvalho Chehab 	if (err) {
1234786baecfSMauro Carvalho Chehab 		input_free_device(input_dev);
1235786baecfSMauro Carvalho Chehab 		return err;
1236786baecfSMauro Carvalho Chehab 	}
1237786baecfSMauro Carvalho Chehab 
1238786baecfSMauro Carvalho Chehab 	dec->rc_input_dev = input_dev;
1239786baecfSMauro Carvalho Chehab 	if (usb_submit_urb(dec->irq_urb, GFP_KERNEL))
1240786baecfSMauro Carvalho Chehab 		printk("%s: usb_submit_urb failed\n",__func__);
1241786baecfSMauro Carvalho Chehab 	/* enable irq pipe */
1242786baecfSMauro Carvalho Chehab 	ttusb_dec_send_command(dec,0xb0,sizeof(b),b,NULL,NULL);
1243786baecfSMauro Carvalho Chehab 
1244786baecfSMauro Carvalho Chehab 	return 0;
1245786baecfSMauro Carvalho Chehab }
1246786baecfSMauro Carvalho Chehab 
ttusb_dec_init_v_pes(struct ttusb_dec * dec)1247786baecfSMauro Carvalho Chehab static void ttusb_dec_init_v_pes(struct ttusb_dec *dec)
1248786baecfSMauro Carvalho Chehab {
1249786baecfSMauro Carvalho Chehab 	dprintk("%s\n", __func__);
1250786baecfSMauro Carvalho Chehab 
1251786baecfSMauro Carvalho Chehab 	dec->v_pes[0] = 0x00;
1252786baecfSMauro Carvalho Chehab 	dec->v_pes[1] = 0x00;
1253786baecfSMauro Carvalho Chehab 	dec->v_pes[2] = 0x01;
1254786baecfSMauro Carvalho Chehab 	dec->v_pes[3] = 0xe0;
1255786baecfSMauro Carvalho Chehab }
1256786baecfSMauro Carvalho Chehab 
ttusb_dec_init_usb(struct ttusb_dec * dec)1257786baecfSMauro Carvalho Chehab static int ttusb_dec_init_usb(struct ttusb_dec *dec)
1258786baecfSMauro Carvalho Chehab {
1259cf732b5fSAlexey Khoroshilov 	int result;
1260cf732b5fSAlexey Khoroshilov 
1261786baecfSMauro Carvalho Chehab 	dprintk("%s\n", __func__);
1262786baecfSMauro Carvalho Chehab 
1263786baecfSMauro Carvalho Chehab 	mutex_init(&dec->usb_mutex);
1264786baecfSMauro Carvalho Chehab 	mutex_init(&dec->iso_mutex);
1265786baecfSMauro Carvalho Chehab 
1266786baecfSMauro Carvalho Chehab 	dec->command_pipe = usb_sndbulkpipe(dec->udev, COMMAND_PIPE);
1267786baecfSMauro Carvalho Chehab 	dec->result_pipe = usb_rcvbulkpipe(dec->udev, RESULT_PIPE);
1268786baecfSMauro Carvalho Chehab 	dec->in_pipe = usb_rcvisocpipe(dec->udev, IN_PIPE);
1269786baecfSMauro Carvalho Chehab 	dec->out_pipe = usb_sndisocpipe(dec->udev, OUT_PIPE);
1270786baecfSMauro Carvalho Chehab 	dec->irq_pipe = usb_rcvintpipe(dec->udev, IRQ_PIPE);
1271786baecfSMauro Carvalho Chehab 
1272786baecfSMauro Carvalho Chehab 	if(enable_rc) {
1273786baecfSMauro Carvalho Chehab 		dec->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
1274786baecfSMauro Carvalho Chehab 		if(!dec->irq_urb) {
1275786baecfSMauro Carvalho Chehab 			return -ENOMEM;
1276786baecfSMauro Carvalho Chehab 		}
1277786baecfSMauro Carvalho Chehab 		dec->irq_buffer = usb_alloc_coherent(dec->udev,IRQ_PACKET_SIZE,
1278cf732b5fSAlexey Khoroshilov 					GFP_KERNEL, &dec->irq_dma_handle);
1279786baecfSMauro Carvalho Chehab 		if(!dec->irq_buffer) {
1280786baecfSMauro Carvalho Chehab 			usb_free_urb(dec->irq_urb);
1281786baecfSMauro Carvalho Chehab 			return -ENOMEM;
1282786baecfSMauro Carvalho Chehab 		}
1283786baecfSMauro Carvalho Chehab 		usb_fill_int_urb(dec->irq_urb, dec->udev,dec->irq_pipe,
1284786baecfSMauro Carvalho Chehab 				 dec->irq_buffer, IRQ_PACKET_SIZE,
1285786baecfSMauro Carvalho Chehab 				 ttusb_dec_handle_irq, dec, 1);
1286786baecfSMauro Carvalho Chehab 		dec->irq_urb->transfer_dma = dec->irq_dma_handle;
1287786baecfSMauro Carvalho Chehab 		dec->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1288786baecfSMauro Carvalho Chehab 	}
1289786baecfSMauro Carvalho Chehab 
1290cf732b5fSAlexey Khoroshilov 	result = ttusb_dec_alloc_iso_urbs(dec);
1291cf732b5fSAlexey Khoroshilov 	if (result) {
1292cf732b5fSAlexey Khoroshilov 		usb_free_urb(dec->irq_urb);
1293cf732b5fSAlexey Khoroshilov 		usb_free_coherent(dec->udev, IRQ_PACKET_SIZE,
1294cf732b5fSAlexey Khoroshilov 				  dec->irq_buffer, dec->irq_dma_handle);
1295cf732b5fSAlexey Khoroshilov 	}
1296cf732b5fSAlexey Khoroshilov 	return result;
1297786baecfSMauro Carvalho Chehab }
1298786baecfSMauro Carvalho Chehab 
ttusb_dec_boot_dsp(struct ttusb_dec * dec)1299786baecfSMauro Carvalho Chehab static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
1300786baecfSMauro Carvalho Chehab {
1301786baecfSMauro Carvalho Chehab 	int i, j, actual_len, result, size, trans_count;
1302786baecfSMauro Carvalho Chehab 	u8 b0[] = { 0x00, 0x00, 0x00, 0x00,
1303786baecfSMauro Carvalho Chehab 		    0x00, 0x00, 0x00, 0x00,
1304786baecfSMauro Carvalho Chehab 		    0x61, 0x00 };
1305786baecfSMauro Carvalho Chehab 	u8 b1[] = { 0x61 };
1306786baecfSMauro Carvalho Chehab 	u8 *b;
1307786baecfSMauro Carvalho Chehab 	char idstring[21];
1308786baecfSMauro Carvalho Chehab 	const u8 *firmware = NULL;
1309786baecfSMauro Carvalho Chehab 	size_t firmware_size = 0;
1310786baecfSMauro Carvalho Chehab 	u16 firmware_csum = 0;
1311786baecfSMauro Carvalho Chehab 	__be16 firmware_csum_ns;
1312786baecfSMauro Carvalho Chehab 	__be32 firmware_size_nl;
1313786baecfSMauro Carvalho Chehab 	u32 crc32_csum, crc32_check;
1314786baecfSMauro Carvalho Chehab 	__be32 tmp;
1315786baecfSMauro Carvalho Chehab 	const struct firmware *fw_entry = NULL;
1316786baecfSMauro Carvalho Chehab 
1317786baecfSMauro Carvalho Chehab 	dprintk("%s\n", __func__);
1318786baecfSMauro Carvalho Chehab 
1319cf732b5fSAlexey Khoroshilov 	result = request_firmware(&fw_entry, dec->firmware_name, &dec->udev->dev);
1320cf732b5fSAlexey Khoroshilov 	if (result) {
1321786baecfSMauro Carvalho Chehab 		printk(KERN_ERR "%s: Firmware (%s) unavailable.\n",
1322786baecfSMauro Carvalho Chehab 		       __func__, dec->firmware_name);
1323cf732b5fSAlexey Khoroshilov 		return result;
1324786baecfSMauro Carvalho Chehab 	}
1325786baecfSMauro Carvalho Chehab 
1326786baecfSMauro Carvalho Chehab 	firmware = fw_entry->data;
1327786baecfSMauro Carvalho Chehab 	firmware_size = fw_entry->size;
1328786baecfSMauro Carvalho Chehab 
1329786baecfSMauro Carvalho Chehab 	if (firmware_size < 60) {
1330786baecfSMauro Carvalho Chehab 		printk("%s: firmware size too small for DSP code (%zu < 60).\n",
1331786baecfSMauro Carvalho Chehab 			__func__, firmware_size);
1332786baecfSMauro Carvalho Chehab 		release_firmware(fw_entry);
1333cf732b5fSAlexey Khoroshilov 		return -ENOENT;
1334786baecfSMauro Carvalho Chehab 	}
1335786baecfSMauro Carvalho Chehab 
1336786baecfSMauro Carvalho Chehab 	/* a 32 bit checksum over the first 56 bytes of the DSP Code is stored
1337786baecfSMauro Carvalho Chehab 	   at offset 56 of file, so use it to check if the firmware file is
1338786baecfSMauro Carvalho Chehab 	   valid. */
1339786baecfSMauro Carvalho Chehab 	crc32_csum = crc32(~0L, firmware, 56) ^ ~0L;
1340786baecfSMauro Carvalho Chehab 	memcpy(&tmp, &firmware[56], 4);
1341786baecfSMauro Carvalho Chehab 	crc32_check = ntohl(tmp);
1342786baecfSMauro Carvalho Chehab 	if (crc32_csum != crc32_check) {
1343bf769a4eSMauro Carvalho Chehab 		printk("%s: crc32 check of DSP code failed (calculated 0x%08x != 0x%08x in file), file invalid.\n",
1344786baecfSMauro Carvalho Chehab 			__func__, crc32_csum, crc32_check);
1345786baecfSMauro Carvalho Chehab 		release_firmware(fw_entry);
1346cf732b5fSAlexey Khoroshilov 		return -ENOENT;
1347786baecfSMauro Carvalho Chehab 	}
1348786baecfSMauro Carvalho Chehab 	memcpy(idstring, &firmware[36], 20);
1349786baecfSMauro Carvalho Chehab 	idstring[20] = '\0';
1350786baecfSMauro Carvalho Chehab 	printk(KERN_INFO "ttusb_dec: found DSP code \"%s\".\n", idstring);
1351786baecfSMauro Carvalho Chehab 
1352786baecfSMauro Carvalho Chehab 	firmware_size_nl = htonl(firmware_size);
1353786baecfSMauro Carvalho Chehab 	memcpy(b0, &firmware_size_nl, 4);
1354786baecfSMauro Carvalho Chehab 	firmware_csum = crc16(~0, firmware, firmware_size) ^ ~0;
1355786baecfSMauro Carvalho Chehab 	firmware_csum_ns = htons(firmware_csum);
1356786baecfSMauro Carvalho Chehab 	memcpy(&b0[6], &firmware_csum_ns, 2);
1357786baecfSMauro Carvalho Chehab 
1358786baecfSMauro Carvalho Chehab 	result = ttusb_dec_send_command(dec, 0x41, sizeof(b0), b0, NULL, NULL);
1359786baecfSMauro Carvalho Chehab 
1360786baecfSMauro Carvalho Chehab 	if (result) {
1361786baecfSMauro Carvalho Chehab 		release_firmware(fw_entry);
1362786baecfSMauro Carvalho Chehab 		return result;
1363786baecfSMauro Carvalho Chehab 	}
1364786baecfSMauro Carvalho Chehab 
1365786baecfSMauro Carvalho Chehab 	trans_count = 0;
1366786baecfSMauro Carvalho Chehab 	j = 0;
1367786baecfSMauro Carvalho Chehab 
1368786baecfSMauro Carvalho Chehab 	b = kmalloc(ARM_PACKET_SIZE, GFP_KERNEL);
1369786baecfSMauro Carvalho Chehab 	if (b == NULL) {
1370786baecfSMauro Carvalho Chehab 		release_firmware(fw_entry);
1371786baecfSMauro Carvalho Chehab 		return -ENOMEM;
1372786baecfSMauro Carvalho Chehab 	}
1373786baecfSMauro Carvalho Chehab 
1374786baecfSMauro Carvalho Chehab 	for (i = 0; i < firmware_size; i += COMMAND_PACKET_SIZE) {
1375786baecfSMauro Carvalho Chehab 		size = firmware_size - i;
1376786baecfSMauro Carvalho Chehab 		if (size > COMMAND_PACKET_SIZE)
1377786baecfSMauro Carvalho Chehab 			size = COMMAND_PACKET_SIZE;
1378786baecfSMauro Carvalho Chehab 
1379786baecfSMauro Carvalho Chehab 		b[j + 0] = 0xaa;
1380786baecfSMauro Carvalho Chehab 		b[j + 1] = trans_count++;
1381786baecfSMauro Carvalho Chehab 		b[j + 2] = 0xf0;
1382786baecfSMauro Carvalho Chehab 		b[j + 3] = size;
1383786baecfSMauro Carvalho Chehab 		memcpy(&b[j + 4], &firmware[i], size);
1384786baecfSMauro Carvalho Chehab 
1385786baecfSMauro Carvalho Chehab 		j += COMMAND_PACKET_SIZE + 4;
1386786baecfSMauro Carvalho Chehab 
1387786baecfSMauro Carvalho Chehab 		if (j >= ARM_PACKET_SIZE) {
1388786baecfSMauro Carvalho Chehab 			result = usb_bulk_msg(dec->udev, dec->command_pipe, b,
1389786baecfSMauro Carvalho Chehab 					      ARM_PACKET_SIZE, &actual_len,
1390786baecfSMauro Carvalho Chehab 					      100);
1391786baecfSMauro Carvalho Chehab 			j = 0;
1392786baecfSMauro Carvalho Chehab 		} else if (size < COMMAND_PACKET_SIZE) {
1393786baecfSMauro Carvalho Chehab 			result = usb_bulk_msg(dec->udev, dec->command_pipe, b,
1394786baecfSMauro Carvalho Chehab 					      j - COMMAND_PACKET_SIZE + size,
1395786baecfSMauro Carvalho Chehab 					      &actual_len, 100);
1396786baecfSMauro Carvalho Chehab 		}
1397786baecfSMauro Carvalho Chehab 	}
1398786baecfSMauro Carvalho Chehab 
1399786baecfSMauro Carvalho Chehab 	result = ttusb_dec_send_command(dec, 0x43, sizeof(b1), b1, NULL, NULL);
1400786baecfSMauro Carvalho Chehab 
1401786baecfSMauro Carvalho Chehab 	release_firmware(fw_entry);
1402786baecfSMauro Carvalho Chehab 	kfree(b);
1403786baecfSMauro Carvalho Chehab 
1404786baecfSMauro Carvalho Chehab 	return result;
1405786baecfSMauro Carvalho Chehab }
1406786baecfSMauro Carvalho Chehab 
ttusb_dec_init_stb(struct ttusb_dec * dec)1407786baecfSMauro Carvalho Chehab static int ttusb_dec_init_stb(struct ttusb_dec *dec)
1408786baecfSMauro Carvalho Chehab {
1409786baecfSMauro Carvalho Chehab 	int result;
1410786baecfSMauro Carvalho Chehab 	unsigned int mode = 0, model = 0, version = 0;
1411786baecfSMauro Carvalho Chehab 
1412786baecfSMauro Carvalho Chehab 	dprintk("%s\n", __func__);
1413786baecfSMauro Carvalho Chehab 
1414786baecfSMauro Carvalho Chehab 	result = ttusb_dec_get_stb_state(dec, &mode, &model, &version);
1415cf732b5fSAlexey Khoroshilov 	if (result)
1416cf732b5fSAlexey Khoroshilov 		return result;
1417786baecfSMauro Carvalho Chehab 
1418786baecfSMauro Carvalho Chehab 	if (!mode) {
1419786baecfSMauro Carvalho Chehab 		if (version == 0xABCDEFAB)
1420bf769a4eSMauro Carvalho Chehab 			printk(KERN_INFO "ttusb_dec: no version info in Firmware\n");
1421786baecfSMauro Carvalho Chehab 		else
1422bf769a4eSMauro Carvalho Chehab 			printk(KERN_INFO "ttusb_dec: Firmware %x.%02x%c%c\n",
1423786baecfSMauro Carvalho Chehab 			       version >> 24, (version >> 16) & 0xff,
1424786baecfSMauro Carvalho Chehab 			       (version >> 8) & 0xff, version & 0xff);
1425786baecfSMauro Carvalho Chehab 
1426786baecfSMauro Carvalho Chehab 		result = ttusb_dec_boot_dsp(dec);
1427786baecfSMauro Carvalho Chehab 		if (result)
1428786baecfSMauro Carvalho Chehab 			return result;
1429786baecfSMauro Carvalho Chehab 	} else {
1430786baecfSMauro Carvalho Chehab 		/* We can't trust the USB IDs that some firmwares
1431786baecfSMauro Carvalho Chehab 		   give the box */
1432786baecfSMauro Carvalho Chehab 		switch (model) {
1433786baecfSMauro Carvalho Chehab 		case 0x00070001:
1434786baecfSMauro Carvalho Chehab 		case 0x00070008:
1435786baecfSMauro Carvalho Chehab 		case 0x0007000c:
1436786baecfSMauro Carvalho Chehab 			ttusb_dec_set_model(dec, TTUSB_DEC3000S);
1437786baecfSMauro Carvalho Chehab 			break;
1438786baecfSMauro Carvalho Chehab 		case 0x00070009:
1439786baecfSMauro Carvalho Chehab 		case 0x00070013:
1440786baecfSMauro Carvalho Chehab 			ttusb_dec_set_model(dec, TTUSB_DEC2000T);
1441786baecfSMauro Carvalho Chehab 			break;
1442786baecfSMauro Carvalho Chehab 		case 0x00070011:
1443786baecfSMauro Carvalho Chehab 			ttusb_dec_set_model(dec, TTUSB_DEC2540T);
1444786baecfSMauro Carvalho Chehab 			break;
1445786baecfSMauro Carvalho Chehab 		default:
1446bf769a4eSMauro Carvalho Chehab 			printk(KERN_ERR "%s: unknown model returned by firmware (%08x) - please report\n",
1447786baecfSMauro Carvalho Chehab 			       __func__, model);
1448cf732b5fSAlexey Khoroshilov 			return -ENOENT;
1449786baecfSMauro Carvalho Chehab 		}
1450786baecfSMauro Carvalho Chehab 		if (version >= 0x01770000)
1451786baecfSMauro Carvalho Chehab 			dec->can_playback = 1;
1452cf732b5fSAlexey Khoroshilov 	}
1453786baecfSMauro Carvalho Chehab 	return 0;
1454786baecfSMauro Carvalho Chehab }
1455786baecfSMauro Carvalho Chehab 
ttusb_dec_init_dvb(struct ttusb_dec * dec)1456786baecfSMauro Carvalho Chehab static int ttusb_dec_init_dvb(struct ttusb_dec *dec)
1457786baecfSMauro Carvalho Chehab {
1458786baecfSMauro Carvalho Chehab 	int result;
1459786baecfSMauro Carvalho Chehab 
1460786baecfSMauro Carvalho Chehab 	dprintk("%s\n", __func__);
1461786baecfSMauro Carvalho Chehab 
1462786baecfSMauro Carvalho Chehab 	if ((result = dvb_register_adapter(&dec->adapter,
1463786baecfSMauro Carvalho Chehab 					   dec->model_name, THIS_MODULE,
1464786baecfSMauro Carvalho Chehab 					   &dec->udev->dev,
1465786baecfSMauro Carvalho Chehab 					   adapter_nr)) < 0) {
1466786baecfSMauro Carvalho Chehab 		printk("%s: dvb_register_adapter failed: error %d\n",
1467786baecfSMauro Carvalho Chehab 		       __func__, result);
1468786baecfSMauro Carvalho Chehab 
1469786baecfSMauro Carvalho Chehab 		return result;
1470786baecfSMauro Carvalho Chehab 	}
1471786baecfSMauro Carvalho Chehab 
1472786baecfSMauro Carvalho Chehab 	dec->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
1473786baecfSMauro Carvalho Chehab 
1474786baecfSMauro Carvalho Chehab 	dec->demux.priv = (void *)dec;
1475786baecfSMauro Carvalho Chehab 	dec->demux.filternum = 31;
1476786baecfSMauro Carvalho Chehab 	dec->demux.feednum = 31;
1477786baecfSMauro Carvalho Chehab 	dec->demux.start_feed = ttusb_dec_start_feed;
1478786baecfSMauro Carvalho Chehab 	dec->demux.stop_feed = ttusb_dec_stop_feed;
1479786baecfSMauro Carvalho Chehab 	dec->demux.write_to_decoder = NULL;
1480786baecfSMauro Carvalho Chehab 
1481786baecfSMauro Carvalho Chehab 	if ((result = dvb_dmx_init(&dec->demux)) < 0) {
1482786baecfSMauro Carvalho Chehab 		printk("%s: dvb_dmx_init failed: error %d\n", __func__,
1483786baecfSMauro Carvalho Chehab 		       result);
1484786baecfSMauro Carvalho Chehab 
1485786baecfSMauro Carvalho Chehab 		dvb_unregister_adapter(&dec->adapter);
1486786baecfSMauro Carvalho Chehab 
1487786baecfSMauro Carvalho Chehab 		return result;
1488786baecfSMauro Carvalho Chehab 	}
1489786baecfSMauro Carvalho Chehab 
1490786baecfSMauro Carvalho Chehab 	dec->dmxdev.filternum = 32;
1491786baecfSMauro Carvalho Chehab 	dec->dmxdev.demux = &dec->demux.dmx;
1492786baecfSMauro Carvalho Chehab 	dec->dmxdev.capabilities = 0;
1493786baecfSMauro Carvalho Chehab 
1494786baecfSMauro Carvalho Chehab 	if ((result = dvb_dmxdev_init(&dec->dmxdev, &dec->adapter)) < 0) {
1495786baecfSMauro Carvalho Chehab 		printk("%s: dvb_dmxdev_init failed: error %d\n",
1496786baecfSMauro Carvalho Chehab 		       __func__, result);
1497786baecfSMauro Carvalho Chehab 
1498786baecfSMauro Carvalho Chehab 		dvb_dmx_release(&dec->demux);
1499786baecfSMauro Carvalho Chehab 		dvb_unregister_adapter(&dec->adapter);
1500786baecfSMauro Carvalho Chehab 
1501786baecfSMauro Carvalho Chehab 		return result;
1502786baecfSMauro Carvalho Chehab 	}
1503786baecfSMauro Carvalho Chehab 
1504786baecfSMauro Carvalho Chehab 	dec->frontend.source = DMX_FRONTEND_0;
1505786baecfSMauro Carvalho Chehab 
1506786baecfSMauro Carvalho Chehab 	if ((result = dec->demux.dmx.add_frontend(&dec->demux.dmx,
1507786baecfSMauro Carvalho Chehab 						  &dec->frontend)) < 0) {
1508786baecfSMauro Carvalho Chehab 		printk("%s: dvb_dmx_init failed: error %d\n", __func__,
1509786baecfSMauro Carvalho Chehab 		       result);
1510786baecfSMauro Carvalho Chehab 
1511786baecfSMauro Carvalho Chehab 		dvb_dmxdev_release(&dec->dmxdev);
1512786baecfSMauro Carvalho Chehab 		dvb_dmx_release(&dec->demux);
1513786baecfSMauro Carvalho Chehab 		dvb_unregister_adapter(&dec->adapter);
1514786baecfSMauro Carvalho Chehab 
1515786baecfSMauro Carvalho Chehab 		return result;
1516786baecfSMauro Carvalho Chehab 	}
1517786baecfSMauro Carvalho Chehab 
1518786baecfSMauro Carvalho Chehab 	if ((result = dec->demux.dmx.connect_frontend(&dec->demux.dmx,
1519786baecfSMauro Carvalho Chehab 						      &dec->frontend)) < 0) {
1520786baecfSMauro Carvalho Chehab 		printk("%s: dvb_dmx_init failed: error %d\n", __func__,
1521786baecfSMauro Carvalho Chehab 		       result);
1522786baecfSMauro Carvalho Chehab 
1523786baecfSMauro Carvalho Chehab 		dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend);
1524786baecfSMauro Carvalho Chehab 		dvb_dmxdev_release(&dec->dmxdev);
1525786baecfSMauro Carvalho Chehab 		dvb_dmx_release(&dec->demux);
1526786baecfSMauro Carvalho Chehab 		dvb_unregister_adapter(&dec->adapter);
1527786baecfSMauro Carvalho Chehab 
1528786baecfSMauro Carvalho Chehab 		return result;
1529786baecfSMauro Carvalho Chehab 	}
1530786baecfSMauro Carvalho Chehab 
1531786baecfSMauro Carvalho Chehab 	dvb_net_init(&dec->adapter, &dec->dvb_net, &dec->demux.dmx);
1532786baecfSMauro Carvalho Chehab 
1533786baecfSMauro Carvalho Chehab 	return 0;
1534786baecfSMauro Carvalho Chehab }
1535786baecfSMauro Carvalho Chehab 
ttusb_dec_exit_dvb(struct ttusb_dec * dec)1536786baecfSMauro Carvalho Chehab static void ttusb_dec_exit_dvb(struct ttusb_dec *dec)
1537786baecfSMauro Carvalho Chehab {
1538786baecfSMauro Carvalho Chehab 	dprintk("%s\n", __func__);
1539786baecfSMauro Carvalho Chehab 
1540786baecfSMauro Carvalho Chehab 	dvb_net_release(&dec->dvb_net);
1541786baecfSMauro Carvalho Chehab 	dec->demux.dmx.close(&dec->demux.dmx);
1542786baecfSMauro Carvalho Chehab 	dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend);
1543786baecfSMauro Carvalho Chehab 	dvb_dmxdev_release(&dec->dmxdev);
1544786baecfSMauro Carvalho Chehab 	dvb_dmx_release(&dec->demux);
1545786baecfSMauro Carvalho Chehab 	if (dec->fe) {
1546786baecfSMauro Carvalho Chehab 		dvb_unregister_frontend(dec->fe);
1547517a2813SHyunwoo Kim 		dvb_frontend_detach(dec->fe);
1548786baecfSMauro Carvalho Chehab 	}
1549786baecfSMauro Carvalho Chehab 	dvb_unregister_adapter(&dec->adapter);
1550786baecfSMauro Carvalho Chehab }
1551786baecfSMauro Carvalho Chehab 
ttusb_dec_exit_rc(struct ttusb_dec * dec)1552786baecfSMauro Carvalho Chehab static void ttusb_dec_exit_rc(struct ttusb_dec *dec)
1553786baecfSMauro Carvalho Chehab {
1554786baecfSMauro Carvalho Chehab 	dprintk("%s\n", __func__);
1555786baecfSMauro Carvalho Chehab 
1556786baecfSMauro Carvalho Chehab 	if (dec->rc_input_dev) {
1557786baecfSMauro Carvalho Chehab 		input_unregister_device(dec->rc_input_dev);
1558786baecfSMauro Carvalho Chehab 		dec->rc_input_dev = NULL;
1559786baecfSMauro Carvalho Chehab 	}
1560786baecfSMauro Carvalho Chehab }
1561786baecfSMauro Carvalho Chehab 
1562786baecfSMauro Carvalho Chehab 
ttusb_dec_exit_usb(struct ttusb_dec * dec)1563786baecfSMauro Carvalho Chehab static void ttusb_dec_exit_usb(struct ttusb_dec *dec)
1564786baecfSMauro Carvalho Chehab {
1565786baecfSMauro Carvalho Chehab 	int i;
1566786baecfSMauro Carvalho Chehab 
1567786baecfSMauro Carvalho Chehab 	dprintk("%s\n", __func__);
1568786baecfSMauro Carvalho Chehab 
1569cf732b5fSAlexey Khoroshilov 	if (enable_rc) {
1570cf732b5fSAlexey Khoroshilov 		/* we have to check whether the irq URB is already submitted.
1571cf732b5fSAlexey Khoroshilov 		 * As the irq is submitted after the interface is changed,
1572cf732b5fSAlexey Khoroshilov 		 * this is the best method i figured out.
1573cf732b5fSAlexey Khoroshilov 		 * Any others?*/
1574cf732b5fSAlexey Khoroshilov 		if (dec->interface == TTUSB_DEC_INTERFACE_IN)
1575cf732b5fSAlexey Khoroshilov 			usb_kill_urb(dec->irq_urb);
1576cf732b5fSAlexey Khoroshilov 
1577cf732b5fSAlexey Khoroshilov 		usb_free_urb(dec->irq_urb);
1578cf732b5fSAlexey Khoroshilov 
1579cf732b5fSAlexey Khoroshilov 		usb_free_coherent(dec->udev, IRQ_PACKET_SIZE,
1580cf732b5fSAlexey Khoroshilov 				  dec->irq_buffer, dec->irq_dma_handle);
1581cf732b5fSAlexey Khoroshilov 	}
1582cf732b5fSAlexey Khoroshilov 
1583786baecfSMauro Carvalho Chehab 	dec->iso_stream_count = 0;
1584786baecfSMauro Carvalho Chehab 
1585786baecfSMauro Carvalho Chehab 	for (i = 0; i < ISO_BUF_COUNT; i++)
1586786baecfSMauro Carvalho Chehab 		usb_kill_urb(dec->iso_urb[i]);
1587786baecfSMauro Carvalho Chehab 
1588786baecfSMauro Carvalho Chehab 	ttusb_dec_free_iso_urbs(dec);
1589786baecfSMauro Carvalho Chehab }
1590786baecfSMauro Carvalho Chehab 
ttusb_dec_exit_tasklet(struct ttusb_dec * dec)1591786baecfSMauro Carvalho Chehab static void ttusb_dec_exit_tasklet(struct ttusb_dec *dec)
1592786baecfSMauro Carvalho Chehab {
1593786baecfSMauro Carvalho Chehab 	struct list_head *item;
1594786baecfSMauro Carvalho Chehab 	struct urb_frame *frame;
1595786baecfSMauro Carvalho Chehab 
1596786baecfSMauro Carvalho Chehab 	tasklet_kill(&dec->urb_tasklet);
1597786baecfSMauro Carvalho Chehab 
1598786baecfSMauro Carvalho Chehab 	while ((item = dec->urb_frame_list.next) != &dec->urb_frame_list) {
1599786baecfSMauro Carvalho Chehab 		frame = list_entry(item, struct urb_frame, urb_frame_list);
1600786baecfSMauro Carvalho Chehab 		list_del(&frame->urb_frame_list);
1601786baecfSMauro Carvalho Chehab 		kfree(frame);
1602786baecfSMauro Carvalho Chehab 	}
1603786baecfSMauro Carvalho Chehab }
1604786baecfSMauro Carvalho Chehab 
ttusb_dec_init_filters(struct ttusb_dec * dec)1605786baecfSMauro Carvalho Chehab static void ttusb_dec_init_filters(struct ttusb_dec *dec)
1606786baecfSMauro Carvalho Chehab {
1607786baecfSMauro Carvalho Chehab 	INIT_LIST_HEAD(&dec->filter_info_list);
1608786baecfSMauro Carvalho Chehab 	spin_lock_init(&dec->filter_info_list_lock);
1609786baecfSMauro Carvalho Chehab }
1610786baecfSMauro Carvalho Chehab 
ttusb_dec_exit_filters(struct ttusb_dec * dec)1611786baecfSMauro Carvalho Chehab static void ttusb_dec_exit_filters(struct ttusb_dec *dec)
1612786baecfSMauro Carvalho Chehab {
1613786baecfSMauro Carvalho Chehab 	struct list_head *item;
1614786baecfSMauro Carvalho Chehab 	struct filter_info *finfo;
1615786baecfSMauro Carvalho Chehab 
1616786baecfSMauro Carvalho Chehab 	while ((item = dec->filter_info_list.next) != &dec->filter_info_list) {
1617786baecfSMauro Carvalho Chehab 		finfo = list_entry(item, struct filter_info, filter_info_list);
1618786baecfSMauro Carvalho Chehab 		list_del(&finfo->filter_info_list);
1619786baecfSMauro Carvalho Chehab 		kfree(finfo);
1620786baecfSMauro Carvalho Chehab 	}
1621786baecfSMauro Carvalho Chehab }
1622786baecfSMauro Carvalho Chehab 
fe_send_command(struct dvb_frontend * fe,const u8 command,int param_length,const u8 params[],int * result_length,u8 cmd_result[])1623786baecfSMauro Carvalho Chehab static int fe_send_command(struct dvb_frontend* fe, const u8 command,
1624786baecfSMauro Carvalho Chehab 			   int param_length, const u8 params[],
1625786baecfSMauro Carvalho Chehab 			   int *result_length, u8 cmd_result[])
1626786baecfSMauro Carvalho Chehab {
1627786baecfSMauro Carvalho Chehab 	struct ttusb_dec* dec = fe->dvb->priv;
1628786baecfSMauro Carvalho Chehab 	return ttusb_dec_send_command(dec, command, param_length, params, result_length, cmd_result);
1629786baecfSMauro Carvalho Chehab }
1630786baecfSMauro Carvalho Chehab 
16319bca6266SJulia Lawall static const struct ttusbdecfe_config fe_config = {
1632786baecfSMauro Carvalho Chehab 	.send_command = fe_send_command
1633786baecfSMauro Carvalho Chehab };
1634786baecfSMauro Carvalho Chehab 
ttusb_dec_probe(struct usb_interface * intf,const struct usb_device_id * id)1635786baecfSMauro Carvalho Chehab static int ttusb_dec_probe(struct usb_interface *intf,
1636786baecfSMauro Carvalho Chehab 			   const struct usb_device_id *id)
1637786baecfSMauro Carvalho Chehab {
1638786baecfSMauro Carvalho Chehab 	struct usb_device *udev;
1639786baecfSMauro Carvalho Chehab 	struct ttusb_dec *dec;
1640cf732b5fSAlexey Khoroshilov 	int result;
1641786baecfSMauro Carvalho Chehab 
1642786baecfSMauro Carvalho Chehab 	dprintk("%s\n", __func__);
1643786baecfSMauro Carvalho Chehab 
1644786baecfSMauro Carvalho Chehab 	udev = interface_to_usbdev(intf);
1645786baecfSMauro Carvalho Chehab 
1646786baecfSMauro Carvalho Chehab 	if (!(dec = kzalloc(sizeof(struct ttusb_dec), GFP_KERNEL))) {
1647786baecfSMauro Carvalho Chehab 		printk("%s: couldn't allocate memory.\n", __func__);
1648786baecfSMauro Carvalho Chehab 		return -ENOMEM;
1649786baecfSMauro Carvalho Chehab 	}
1650786baecfSMauro Carvalho Chehab 
1651786baecfSMauro Carvalho Chehab 	usb_set_intfdata(intf, (void *)dec);
1652786baecfSMauro Carvalho Chehab 
1653786baecfSMauro Carvalho Chehab 	switch (id->idProduct) {
1654786baecfSMauro Carvalho Chehab 	case 0x1006:
1655786baecfSMauro Carvalho Chehab 		ttusb_dec_set_model(dec, TTUSB_DEC3000S);
1656786baecfSMauro Carvalho Chehab 		break;
1657786baecfSMauro Carvalho Chehab 
1658786baecfSMauro Carvalho Chehab 	case 0x1008:
1659786baecfSMauro Carvalho Chehab 		ttusb_dec_set_model(dec, TTUSB_DEC2000T);
1660786baecfSMauro Carvalho Chehab 		break;
1661786baecfSMauro Carvalho Chehab 
1662786baecfSMauro Carvalho Chehab 	case 0x1009:
1663786baecfSMauro Carvalho Chehab 		ttusb_dec_set_model(dec, TTUSB_DEC2540T);
1664786baecfSMauro Carvalho Chehab 		break;
1665786baecfSMauro Carvalho Chehab 	}
1666786baecfSMauro Carvalho Chehab 
1667786baecfSMauro Carvalho Chehab 	dec->udev = udev;
1668786baecfSMauro Carvalho Chehab 
1669cf732b5fSAlexey Khoroshilov 	result = ttusb_dec_init_usb(dec);
1670cf732b5fSAlexey Khoroshilov 	if (result)
1671cf732b5fSAlexey Khoroshilov 		goto err_usb;
1672cf732b5fSAlexey Khoroshilov 	result = ttusb_dec_init_stb(dec);
1673cf732b5fSAlexey Khoroshilov 	if (result)
1674cf732b5fSAlexey Khoroshilov 		goto err_stb;
1675cf732b5fSAlexey Khoroshilov 	result = ttusb_dec_init_dvb(dec);
1676cf732b5fSAlexey Khoroshilov 	if (result)
1677cf732b5fSAlexey Khoroshilov 		goto err_stb;
1678786baecfSMauro Carvalho Chehab 
1679786baecfSMauro Carvalho Chehab 	dec->adapter.priv = dec;
1680786baecfSMauro Carvalho Chehab 	switch (id->idProduct) {
1681786baecfSMauro Carvalho Chehab 	case 0x1006:
1682786baecfSMauro Carvalho Chehab 		dec->fe = ttusbdecfe_dvbs_attach(&fe_config);
1683786baecfSMauro Carvalho Chehab 		break;
1684786baecfSMauro Carvalho Chehab 
1685786baecfSMauro Carvalho Chehab 	case 0x1008:
1686786baecfSMauro Carvalho Chehab 	case 0x1009:
1687786baecfSMauro Carvalho Chehab 		dec->fe = ttusbdecfe_dvbt_attach(&fe_config);
1688786baecfSMauro Carvalho Chehab 		break;
1689786baecfSMauro Carvalho Chehab 	}
1690786baecfSMauro Carvalho Chehab 
1691786baecfSMauro Carvalho Chehab 	if (dec->fe == NULL) {
1692786baecfSMauro Carvalho Chehab 		printk("dvb-ttusb-dec: A frontend driver was not found for device [%04x:%04x]\n",
1693786baecfSMauro Carvalho Chehab 		       le16_to_cpu(dec->udev->descriptor.idVendor),
1694786baecfSMauro Carvalho Chehab 		       le16_to_cpu(dec->udev->descriptor.idProduct));
1695786baecfSMauro Carvalho Chehab 	} else {
1696786baecfSMauro Carvalho Chehab 		if (dvb_register_frontend(&dec->adapter, dec->fe)) {
1697786baecfSMauro Carvalho Chehab 			printk("budget-ci: Frontend registration failed!\n");
1698786baecfSMauro Carvalho Chehab 			if (dec->fe->ops.release)
1699786baecfSMauro Carvalho Chehab 				dec->fe->ops.release(dec->fe);
1700786baecfSMauro Carvalho Chehab 			dec->fe = NULL;
1701786baecfSMauro Carvalho Chehab 		}
1702786baecfSMauro Carvalho Chehab 	}
1703786baecfSMauro Carvalho Chehab 
1704786baecfSMauro Carvalho Chehab 	ttusb_dec_init_v_pes(dec);
1705786baecfSMauro Carvalho Chehab 	ttusb_dec_init_filters(dec);
1706786baecfSMauro Carvalho Chehab 	ttusb_dec_init_tasklet(dec);
1707786baecfSMauro Carvalho Chehab 
1708786baecfSMauro Carvalho Chehab 	dec->active = 1;
1709786baecfSMauro Carvalho Chehab 
1710786baecfSMauro Carvalho Chehab 	ttusb_dec_set_interface(dec, TTUSB_DEC_INTERFACE_IN);
1711786baecfSMauro Carvalho Chehab 
1712786baecfSMauro Carvalho Chehab 	if (enable_rc)
1713786baecfSMauro Carvalho Chehab 		ttusb_init_rc(dec);
1714786baecfSMauro Carvalho Chehab 
1715786baecfSMauro Carvalho Chehab 	return 0;
1716cf732b5fSAlexey Khoroshilov err_stb:
1717cf732b5fSAlexey Khoroshilov 	ttusb_dec_exit_usb(dec);
1718cf732b5fSAlexey Khoroshilov err_usb:
1719cf732b5fSAlexey Khoroshilov 	kfree(dec);
1720cf732b5fSAlexey Khoroshilov 	return result;
1721786baecfSMauro Carvalho Chehab }
1722786baecfSMauro Carvalho Chehab 
ttusb_dec_disconnect(struct usb_interface * intf)1723786baecfSMauro Carvalho Chehab static void ttusb_dec_disconnect(struct usb_interface *intf)
1724786baecfSMauro Carvalho Chehab {
1725786baecfSMauro Carvalho Chehab 	struct ttusb_dec *dec = usb_get_intfdata(intf);
1726786baecfSMauro Carvalho Chehab 
1727786baecfSMauro Carvalho Chehab 	usb_set_intfdata(intf, NULL);
1728786baecfSMauro Carvalho Chehab 
1729786baecfSMauro Carvalho Chehab 	dprintk("%s\n", __func__);
1730786baecfSMauro Carvalho Chehab 
1731786baecfSMauro Carvalho Chehab 	if (dec->active) {
1732786baecfSMauro Carvalho Chehab 		ttusb_dec_exit_tasklet(dec);
1733786baecfSMauro Carvalho Chehab 		ttusb_dec_exit_filters(dec);
1734786baecfSMauro Carvalho Chehab 		if(enable_rc)
1735786baecfSMauro Carvalho Chehab 			ttusb_dec_exit_rc(dec);
1736786baecfSMauro Carvalho Chehab 		ttusb_dec_exit_usb(dec);
1737786baecfSMauro Carvalho Chehab 		ttusb_dec_exit_dvb(dec);
1738786baecfSMauro Carvalho Chehab 	}
1739786baecfSMauro Carvalho Chehab 
1740786baecfSMauro Carvalho Chehab 	kfree(dec);
1741786baecfSMauro Carvalho Chehab }
1742786baecfSMauro Carvalho Chehab 
ttusb_dec_set_model(struct ttusb_dec * dec,enum ttusb_dec_model model)1743786baecfSMauro Carvalho Chehab static void ttusb_dec_set_model(struct ttusb_dec *dec,
1744786baecfSMauro Carvalho Chehab 				enum ttusb_dec_model model)
1745786baecfSMauro Carvalho Chehab {
1746786baecfSMauro Carvalho Chehab 	dec->model = model;
1747786baecfSMauro Carvalho Chehab 
1748786baecfSMauro Carvalho Chehab 	switch (model) {
1749786baecfSMauro Carvalho Chehab 	case TTUSB_DEC2000T:
1750786baecfSMauro Carvalho Chehab 		dec->model_name = "DEC2000-t";
1751786baecfSMauro Carvalho Chehab 		dec->firmware_name = "dvb-ttusb-dec-2000t.fw";
1752786baecfSMauro Carvalho Chehab 		break;
1753786baecfSMauro Carvalho Chehab 
1754786baecfSMauro Carvalho Chehab 	case TTUSB_DEC2540T:
1755786baecfSMauro Carvalho Chehab 		dec->model_name = "DEC2540-t";
1756786baecfSMauro Carvalho Chehab 		dec->firmware_name = "dvb-ttusb-dec-2540t.fw";
1757786baecfSMauro Carvalho Chehab 		break;
1758786baecfSMauro Carvalho Chehab 
1759786baecfSMauro Carvalho Chehab 	case TTUSB_DEC3000S:
1760786baecfSMauro Carvalho Chehab 		dec->model_name = "DEC3000-s";
1761786baecfSMauro Carvalho Chehab 		dec->firmware_name = "dvb-ttusb-dec-3000s.fw";
1762786baecfSMauro Carvalho Chehab 		break;
1763786baecfSMauro Carvalho Chehab 	}
1764786baecfSMauro Carvalho Chehab }
1765786baecfSMauro Carvalho Chehab 
17667fb2e072SArvind Yadav static const struct usb_device_id ttusb_dec_table[] = {
1767786baecfSMauro Carvalho Chehab 	{USB_DEVICE(0x0b48, 0x1006)},	/* DEC3000-s */
1768786baecfSMauro Carvalho Chehab 	/*{USB_DEVICE(0x0b48, 0x1007)},	   Unconfirmed */
1769786baecfSMauro Carvalho Chehab 	{USB_DEVICE(0x0b48, 0x1008)},	/* DEC2000-t */
1770786baecfSMauro Carvalho Chehab 	{USB_DEVICE(0x0b48, 0x1009)},	/* DEC2540-t */
1771786baecfSMauro Carvalho Chehab 	{}
1772786baecfSMauro Carvalho Chehab };
1773786baecfSMauro Carvalho Chehab 
1774786baecfSMauro Carvalho Chehab static struct usb_driver ttusb_dec_driver = {
1775786baecfSMauro Carvalho Chehab 	.name		= "ttusb-dec",
1776786baecfSMauro Carvalho Chehab 	.probe		= ttusb_dec_probe,
1777786baecfSMauro Carvalho Chehab 	.disconnect	= ttusb_dec_disconnect,
1778786baecfSMauro Carvalho Chehab 	.id_table	= ttusb_dec_table,
1779786baecfSMauro Carvalho Chehab };
1780786baecfSMauro Carvalho Chehab 
1781786baecfSMauro Carvalho Chehab module_usb_driver(ttusb_dec_driver);
1782786baecfSMauro Carvalho Chehab 
1783786baecfSMauro Carvalho Chehab MODULE_AUTHOR("Alex Woods <linux-dvb@giblets.org>");
1784786baecfSMauro Carvalho Chehab MODULE_DESCRIPTION(DRIVER_NAME);
1785786baecfSMauro Carvalho Chehab MODULE_LICENSE("GPL");
1786786baecfSMauro Carvalho Chehab MODULE_DEVICE_TABLE(usb, ttusb_dec_table);
1787