firedtv-dvb.c 8.9 KB
Newer Older
1
/*
2
 * FireDTV driver (formerly known as FireSAT)
3
 *
4 5
 * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
 * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
6 7 8 9 10 11 12
 *
 *	This program is free software; you can redistribute it and/or
 *	modify it under the terms of the GNU General Public License as
 *	published by the Free Software Foundation; either version 2 of
 *	the License, or (at your option) any later version.
 */

S
Stefan Richter 已提交
13 14
#include <linux/bitops.h>
#include <linux/device.h>
G
Greg Kroah-Hartman 已提交
15
#include <linux/errno.h>
16
#include <linux/kernel.h>
S
Stefan Richter 已提交
17 18
#include <linux/mod_devicetable.h>
#include <linux/module.h>
19
#include <linux/mutex.h>
S
Stefan Richter 已提交
20 21
#include <linux/slab.h>
#include <linux/string.h>
22
#include <linux/types.h>
S
Stefan Richter 已提交
23 24
#include <linux/wait.h>
#include <linux/workqueue.h>
25

S
Stefan Richter 已提交
26
#include <dmxdev.h>
27
#include <dvb_demux.h>
G
Greg Kroah-Hartman 已提交
28
#include <dvbdev.h>
S
Stefan Richter 已提交
29
#include <dvb_frontend.h>
G
Greg Kroah-Hartman 已提交
30

31
#include "firedtv.h"
G
Greg Kroah-Hartman 已提交
32

S
Stefan Richter 已提交
33
static int alloc_channel(struct firedtv *fdtv)
G
Greg Kroah-Hartman 已提交
34
{
S
Stefan Richter 已提交
35
	int i;
G
Greg Kroah-Hartman 已提交
36

S
Stefan Richter 已提交
37 38
	for (i = 0; i < 16; i++)
		if (!__test_and_set_bit(i, &fdtv->channel_active))
39
			break;
S
Stefan Richter 已提交
40
	return i;
G
Greg Kroah-Hartman 已提交
41 42
}

S
Stefan Richter 已提交
43
static void collect_channels(struct firedtv *fdtv, int *pidc, u16 pid[])
G
Greg Kroah-Hartman 已提交
44
{
S
Stefan Richter 已提交
45
	int i, n;
G
Greg Kroah-Hartman 已提交
46

S
Stefan Richter 已提交
47 48 49 50
	for (i = 0, n = 0; i < 16; i++)
		if (test_bit(i, &fdtv->channel_active))
			pid[n++] = fdtv->channel_pid[i];
	*pidc = n;
G
Greg Kroah-Hartman 已提交
51 52
}

S
Stefan Richter 已提交
53
static inline void dealloc_channel(struct firedtv *fdtv, int i)
G
Greg Kroah-Hartman 已提交
54
{
S
Stefan Richter 已提交
55
	__clear_bit(i, &fdtv->channel_active);
G
Greg Kroah-Hartman 已提交
56 57
}

58
int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed)
G
Greg Kroah-Hartman 已提交
59
{
S
Stefan Richter 已提交
60 61
	struct firedtv *fdtv = dvbdmxfeed->demux->priv;
	int pidc, c, ret;
G
Greg Kroah-Hartman 已提交
62 63 64 65 66 67 68
	u16 pids[16];

	switch (dvbdmxfeed->type) {
	case DMX_TYPE_TS:
	case DMX_TYPE_SEC:
		break;
	default:
S
Stefan Richter 已提交
69 70
		dev_err(fdtv->device, "can't start dmx feed: invalid type %u\n",
			dvbdmxfeed->type);
G
Greg Kroah-Hartman 已提交
71 72 73
		return -EINVAL;
	}

S
Stefan Richter 已提交
74 75 76
	if (mutex_lock_interruptible(&fdtv->demux_mutex))
		return -EINTR;

G
Greg Kroah-Hartman 已提交
77 78 79 80 81 82 83
	if (dvbdmxfeed->type == DMX_TYPE_TS) {
		switch (dvbdmxfeed->pes_type) {
		case DMX_TS_PES_VIDEO:
		case DMX_TS_PES_AUDIO:
		case DMX_TS_PES_TELETEXT:
		case DMX_TS_PES_PCR:
		case DMX_TS_PES_OTHER:
S
Stefan Richter 已提交
84
			c = alloc_channel(fdtv);
G
Greg Kroah-Hartman 已提交
85 86
			break;
		default:
S
Stefan Richter 已提交
87 88 89 90 91
			dev_err(fdtv->device,
				"can't start dmx feed: invalid pes type %u\n",
				dvbdmxfeed->pes_type);
			ret = -EINVAL;
			goto out;
G
Greg Kroah-Hartman 已提交
92 93
		}
	} else {
S
Stefan Richter 已提交
94
		c = alloc_channel(fdtv);
G
Greg Kroah-Hartman 已提交
95 96
	}

S
Stefan Richter 已提交
97 98 99 100
	if (c > 15) {
		dev_err(fdtv->device, "can't start dmx feed: busy\n");
		ret = -EBUSY;
		goto out;
G
Greg Kroah-Hartman 已提交
101 102
	}

S
Stefan Richter 已提交
103 104 105
	dvbdmxfeed->priv = (typeof(dvbdmxfeed->priv))(unsigned long)c;
	fdtv->channel_pid[c] = dvbdmxfeed->pid;
	collect_channels(fdtv, &pidc, pids);
G
Greg Kroah-Hartman 已提交
106

107
	if (dvbdmxfeed->pid == 8192) {
S
Stefan Richter 已提交
108 109 110 111 112
		ret = avc_tuner_get_ts(fdtv);
		if (ret) {
			dealloc_channel(fdtv, c);
			dev_err(fdtv->device, "can't get TS\n");
			goto out;
G
Greg Kroah-Hartman 已提交
113
		}
114
	} else {
S
Stefan Richter 已提交
115 116 117 118 119
		ret = avc_tuner_set_pids(fdtv, pidc, pids);
		if (ret) {
			dealloc_channel(fdtv, c);
			dev_err(fdtv->device, "can't set PIDs\n");
			goto out;
G
Greg Kroah-Hartman 已提交
120 121
		}
	}
S
Stefan Richter 已提交
122 123
out:
	mutex_unlock(&fdtv->demux_mutex);
G
Greg Kroah-Hartman 已提交
124

S
Stefan Richter 已提交
125
	return ret;
G
Greg Kroah-Hartman 已提交
126 127
}

128
int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
G
Greg Kroah-Hartman 已提交
129 130
{
	struct dvb_demux *demux = dvbdmxfeed->demux;
S
Stefan Richter 已提交
131 132
	struct firedtv *fdtv = demux->priv;
	int pidc, c, ret;
G
Greg Kroah-Hartman 已提交
133 134
	u16 pids[16];

S
Stefan Richter 已提交
135 136 137
	if (dvbdmxfeed->type == DMX_TYPE_TS &&
	    !((dvbdmxfeed->ts_type & TS_PACKET) &&
	      (demux->dmx.frontend->source != DMX_MEMORY_FE))) {
G
Greg Kroah-Hartman 已提交
138 139 140

		if (dvbdmxfeed->ts_type & TS_DECODER) {
			if (dvbdmxfeed->pes_type >= DMX_TS_PES_OTHER ||
S
Stefan Richter 已提交
141
			    !demux->pesfilter[dvbdmxfeed->pes_type])
G
Greg Kroah-Hartman 已提交
142 143 144
				return -EINVAL;

			demux->pids[dvbdmxfeed->pes_type] |= 0x8000;
145
			demux->pesfilter[dvbdmxfeed->pes_type] = NULL;
G
Greg Kroah-Hartman 已提交
146 147 148
		}

		if (!(dvbdmxfeed->ts_type & TS_DECODER &&
S
Stefan Richter 已提交
149
		      dvbdmxfeed->pes_type < DMX_TS_PES_OTHER))
G
Greg Kroah-Hartman 已提交
150 151 152
			return 0;
	}

153
	if (mutex_lock_interruptible(&fdtv->demux_mutex))
G
Greg Kroah-Hartman 已提交
154 155
		return -EINTR;

S
Stefan Richter 已提交
156 157 158
	c = (unsigned long)dvbdmxfeed->priv;
	dealloc_channel(fdtv, c);
	collect_channels(fdtv, &pidc, pids);
G
Greg Kroah-Hartman 已提交
159

S
Stefan Richter 已提交
160
	ret = avc_tuner_set_pids(fdtv, pidc, pids);
G
Greg Kroah-Hartman 已提交
161

162
	mutex_unlock(&fdtv->demux_mutex);
S
Stefan Richter 已提交
163 164

	return ret;
G
Greg Kroah-Hartman 已提交
165 166
}

S
Stefan Richter 已提交
167 168 169
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);

int fdtv_dvb_register(struct firedtv *fdtv)
G
Greg Kroah-Hartman 已提交
170
{
171
	int err;
G
Greg Kroah-Hartman 已提交
172

S
Stefan Richter 已提交
173 174
	err = dvb_register_adapter(&fdtv->adapter, fdtv_model_names[fdtv->type],
				   THIS_MODULE, fdtv->device, adapter_nr);
175
	if (err < 0)
176
		goto fail_log;
G
Greg Kroah-Hartman 已提交
177

178
	/*DMX_TS_FILTERING | DMX_SECTION_FILTERING*/
179
	fdtv->demux.dmx.capabilities = 0;
G
Greg Kroah-Hartman 已提交
180

181 182 183 184 185 186
	fdtv->demux.priv	= fdtv;
	fdtv->demux.filternum	= 16;
	fdtv->demux.feednum	= 16;
	fdtv->demux.start_feed	= fdtv_start_feed;
	fdtv->demux.stop_feed	= fdtv_stop_feed;
	fdtv->demux.write_to_decoder = NULL;
G
Greg Kroah-Hartman 已提交
187

188
	err = dvb_dmx_init(&fdtv->demux);
189 190
	if (err)
		goto fail_unreg_adapter;
G
Greg Kroah-Hartman 已提交
191

S
Stefan Richter 已提交
192 193 194
	fdtv->dmxdev.filternum    = 16;
	fdtv->dmxdev.demux        = &fdtv->demux.dmx;
	fdtv->dmxdev.capabilities = 0;
G
Greg Kroah-Hartman 已提交
195

196
	err = dvb_dmxdev_init(&fdtv->dmxdev, &fdtv->adapter);
197 198
	if (err)
		goto fail_dmx_release;
G
Greg Kroah-Hartman 已提交
199

200
	fdtv->frontend.source = DMX_FRONTEND_0;
G
Greg Kroah-Hartman 已提交
201

S
Stefan Richter 已提交
202
	err = fdtv->demux.dmx.add_frontend(&fdtv->demux.dmx, &fdtv->frontend);
203 204
	if (err)
		goto fail_dmxdev_release;
G
Greg Kroah-Hartman 已提交
205

206
	err = fdtv->demux.dmx.connect_frontend(&fdtv->demux.dmx,
S
Stefan Richter 已提交
207
					       &fdtv->frontend);
208 209
	if (err)
		goto fail_rem_frontend;
G
Greg Kroah-Hartman 已提交
210

211
	dvb_net_init(&fdtv->adapter, &fdtv->dvbnet, &fdtv->demux.dmx);
G
Greg Kroah-Hartman 已提交
212

213 214
	fdtv_frontend_init(fdtv);
	err = dvb_register_frontend(&fdtv->adapter, &fdtv->fe);
215 216
	if (err)
		goto fail_net_release;
G
Greg Kroah-Hartman 已提交
217

218
	err = fdtv_ca_register(fdtv);
219
	if (err)
S
Stefan Richter 已提交
220 221
		dev_info(fdtv->device,
			 "Conditional Access Module not enabled\n");
222
	return 0;
G
Greg Kroah-Hartman 已提交
223

224
fail_net_release:
225 226
	dvb_net_release(&fdtv->dvbnet);
	fdtv->demux.dmx.close(&fdtv->demux.dmx);
227
fail_rem_frontend:
S
Stefan Richter 已提交
228
	fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend);
229
fail_dmxdev_release:
230
	dvb_dmxdev_release(&fdtv->dmxdev);
231
fail_dmx_release:
232
	dvb_dmx_release(&fdtv->demux);
233
fail_unreg_adapter:
234
	dvb_unregister_adapter(&fdtv->adapter);
235
fail_log:
S
Stefan Richter 已提交
236
	dev_err(fdtv->device, "DVB initialization failed\n");
237
	return err;
G
Greg Kroah-Hartman 已提交
238
}
239

S
Stefan Richter 已提交
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
void fdtv_dvb_unregister(struct firedtv *fdtv)
{
	fdtv_ca_release(fdtv);
	dvb_unregister_frontend(&fdtv->fe);
	dvb_net_release(&fdtv->dvbnet);
	fdtv->demux.dmx.close(&fdtv->demux.dmx);
	fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend);
	dvb_dmxdev_release(&fdtv->dmxdev);
	dvb_dmx_release(&fdtv->demux);
	dvb_unregister_adapter(&fdtv->adapter);
}

const char *fdtv_model_names[] = {
	[FIREDTV_UNKNOWN] = "unknown type",
	[FIREDTV_DVB_S]   = "FireDTV S/CI",
	[FIREDTV_DVB_C]   = "FireDTV C/CI",
	[FIREDTV_DVB_T]   = "FireDTV T/CI",
	[FIREDTV_DVB_S2]  = "FireDTV S2  ",
};

struct firedtv *fdtv_alloc(struct device *dev,
			   const struct firedtv_backend *backend,
			   const char *name, size_t name_len)
{
	struct firedtv *fdtv;
	int i;

	fdtv = kzalloc(sizeof(*fdtv), GFP_KERNEL);
	if (!fdtv)
		return NULL;

271
	dev_set_drvdata(dev, fdtv);
S
Stefan Richter 已提交
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
	fdtv->device		= dev;
	fdtv->isochannel	= -1;
	fdtv->voltage		= 0xff;
	fdtv->tone		= 0xff;
	fdtv->backend		= backend;

	mutex_init(&fdtv->avc_mutex);
	init_waitqueue_head(&fdtv->avc_wait);
	fdtv->avc_reply_received = true;
	mutex_init(&fdtv->demux_mutex);
	INIT_WORK(&fdtv->remote_ctrl_work, avc_remote_ctrl_work);

	for (i = ARRAY_SIZE(fdtv_model_names); --i; )
		if (strlen(fdtv_model_names[i]) <= name_len &&
		    strncmp(name, fdtv_model_names[i], name_len) == 0)
			break;
	fdtv->type = i;

	return fdtv;
}

#define MATCH_FLAGS (IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID | \
		     IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION)

#define DIGITAL_EVERYWHERE_OUI	0x001287
#define AVC_UNIT_SPEC_ID_ENTRY	0x00a02d
#define AVC_SW_VERSION_ENTRY	0x010001

300
const struct ieee1394_device_id fdtv_id_table[] = {
S
Stefan Richter 已提交
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
	{
		/* FloppyDTV S/CI and FloppyDTV S2 */
		.match_flags	= MATCH_FLAGS,
		.vendor_id	= DIGITAL_EVERYWHERE_OUI,
		.model_id	= 0x000024,
		.specifier_id	= AVC_UNIT_SPEC_ID_ENTRY,
		.version	= AVC_SW_VERSION_ENTRY,
	}, {
		/* FloppyDTV T/CI */
		.match_flags	= MATCH_FLAGS,
		.vendor_id	= DIGITAL_EVERYWHERE_OUI,
		.model_id	= 0x000025,
		.specifier_id	= AVC_UNIT_SPEC_ID_ENTRY,
		.version	= AVC_SW_VERSION_ENTRY,
	}, {
		/* FloppyDTV C/CI */
		.match_flags	= MATCH_FLAGS,
		.vendor_id	= DIGITAL_EVERYWHERE_OUI,
		.model_id	= 0x000026,
		.specifier_id	= AVC_UNIT_SPEC_ID_ENTRY,
		.version	= AVC_SW_VERSION_ENTRY,
	}, {
		/* FireDTV S/CI and FloppyDTV S2 */
		.match_flags	= MATCH_FLAGS,
		.vendor_id	= DIGITAL_EVERYWHERE_OUI,
		.model_id	= 0x000034,
		.specifier_id	= AVC_UNIT_SPEC_ID_ENTRY,
		.version	= AVC_SW_VERSION_ENTRY,
	}, {
		/* FireDTV T/CI */
		.match_flags	= MATCH_FLAGS,
		.vendor_id	= DIGITAL_EVERYWHERE_OUI,
		.model_id	= 0x000035,
		.specifier_id	= AVC_UNIT_SPEC_ID_ENTRY,
		.version	= AVC_SW_VERSION_ENTRY,
	}, {
		/* FireDTV C/CI */
		.match_flags	= MATCH_FLAGS,
		.vendor_id	= DIGITAL_EVERYWHERE_OUI,
		.model_id	= 0x000036,
		.specifier_id	= AVC_UNIT_SPEC_ID_ENTRY,
		.version	= AVC_SW_VERSION_ENTRY,
	}, {}
};
MODULE_DEVICE_TABLE(ieee1394, fdtv_id_table);

static int __init fdtv_init(void)
{
349 350 351 352 353 354 355 356 357 358 359
	int ret;

	ret = fdtv_fw_init();
	if (ret < 0)
		return ret;

	ret = fdtv_1394_init();
	if (ret < 0)
		fdtv_fw_exit();

	return ret;
S
Stefan Richter 已提交
360 361 362 363 364
}

static void __exit fdtv_exit(void)
{
	fdtv_1394_exit();
365
	fdtv_fw_exit();
S
Stefan Richter 已提交
366 367 368 369
}

module_init(fdtv_init);
module_exit(fdtv_exit);
370

S
Stefan Richter 已提交
371 372 373 374 375
MODULE_AUTHOR("Andreas Monitzer <andy@monitzer.com>");
MODULE_AUTHOR("Ben Backx <ben@bbackx.com>");
MODULE_DESCRIPTION("FireDTV DVB Driver");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("FireDTV DVB");