• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * FireDTV driver (formerly known as FireSAT)
3  *
4  * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
5  * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
6  *
7  *	This program is free software; you can redistribute it and/or
8  *	modify it under the terms of the GNU General Public License as
9  *	published by the Free Software Foundation; either version 2 of
10  *	the License, or (at your option) any later version.
11  */
12 
13 #include <linux/bitops.h>
14 #include <linux/device.h>
15 #include <linux/errno.h>
16 #include <linux/kernel.h>
17 #include <linux/mod_devicetable.h>
18 #include <linux/module.h>
19 #include <linux/mutex.h>
20 #include <linux/slab.h>
21 #include <linux/string.h>
22 #include <linux/types.h>
23 #include <linux/wait.h>
24 #include <linux/workqueue.h>
25 
26 #include <dmxdev.h>
27 #include <dvb_demux.h>
28 #include <dvbdev.h>
29 #include <dvb_frontend.h>
30 
31 #include "firedtv.h"
32 
alloc_channel(struct firedtv * fdtv)33 static int alloc_channel(struct firedtv *fdtv)
34 {
35 	int i;
36 
37 	for (i = 0; i < 16; i++)
38 		if (!__test_and_set_bit(i, &fdtv->channel_active))
39 			break;
40 	return i;
41 }
42 
collect_channels(struct firedtv * fdtv,int * pidc,u16 pid[])43 static void collect_channels(struct firedtv *fdtv, int *pidc, u16 pid[])
44 {
45 	int i, n;
46 
47 	for (i = 0, n = 0; i < 16; i++)
48 		if (test_bit(i, &fdtv->channel_active))
49 			pid[n++] = fdtv->channel_pid[i];
50 	*pidc = n;
51 }
52 
dealloc_channel(struct firedtv * fdtv,int i)53 static inline void dealloc_channel(struct firedtv *fdtv, int i)
54 {
55 	__clear_bit(i, &fdtv->channel_active);
56 }
57 
fdtv_start_feed(struct dvb_demux_feed * dvbdmxfeed)58 int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed)
59 {
60 	struct firedtv *fdtv = dvbdmxfeed->demux->priv;
61 	int pidc, c, ret;
62 	u16 pids[16];
63 
64 	switch (dvbdmxfeed->type) {
65 	case DMX_TYPE_TS:
66 	case DMX_TYPE_SEC:
67 		break;
68 	default:
69 		dev_err(fdtv->device, "can't start dmx feed: invalid type %u\n",
70 			dvbdmxfeed->type);
71 		return -EINVAL;
72 	}
73 
74 	if (mutex_lock_interruptible(&fdtv->demux_mutex))
75 		return -EINTR;
76 
77 	if (dvbdmxfeed->type == DMX_TYPE_TS) {
78 		switch (dvbdmxfeed->pes_type) {
79 		case DMX_TS_PES_VIDEO:
80 		case DMX_TS_PES_AUDIO:
81 		case DMX_TS_PES_TELETEXT:
82 		case DMX_TS_PES_PCR:
83 		case DMX_TS_PES_OTHER:
84 			c = alloc_channel(fdtv);
85 			break;
86 		default:
87 			dev_err(fdtv->device,
88 				"can't start dmx feed: invalid pes type %u\n",
89 				dvbdmxfeed->pes_type);
90 			ret = -EINVAL;
91 			goto out;
92 		}
93 	} else {
94 		c = alloc_channel(fdtv);
95 	}
96 
97 	if (c > 15) {
98 		dev_err(fdtv->device, "can't start dmx feed: busy\n");
99 		ret = -EBUSY;
100 		goto out;
101 	}
102 
103 	dvbdmxfeed->priv = (typeof(dvbdmxfeed->priv))(unsigned long)c;
104 	fdtv->channel_pid[c] = dvbdmxfeed->pid;
105 	collect_channels(fdtv, &pidc, pids);
106 
107 	if (dvbdmxfeed->pid == 8192) {
108 		ret = avc_tuner_get_ts(fdtv);
109 		if (ret) {
110 			dealloc_channel(fdtv, c);
111 			dev_err(fdtv->device, "can't get TS\n");
112 			goto out;
113 		}
114 	} else {
115 		ret = avc_tuner_set_pids(fdtv, pidc, pids);
116 		if (ret) {
117 			dealloc_channel(fdtv, c);
118 			dev_err(fdtv->device, "can't set PIDs\n");
119 			goto out;
120 		}
121 	}
122 out:
123 	mutex_unlock(&fdtv->demux_mutex);
124 
125 	return ret;
126 }
127 
fdtv_stop_feed(struct dvb_demux_feed * dvbdmxfeed)128 int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
129 {
130 	struct dvb_demux *demux = dvbdmxfeed->demux;
131 	struct firedtv *fdtv = demux->priv;
132 	int pidc, c, ret;
133 	u16 pids[16];
134 
135 	if (dvbdmxfeed->type == DMX_TYPE_TS &&
136 	    !((dvbdmxfeed->ts_type & TS_PACKET) &&
137 	      (demux->dmx.frontend->source != DMX_MEMORY_FE))) {
138 
139 		if (dvbdmxfeed->ts_type & TS_DECODER) {
140 			if (dvbdmxfeed->pes_type >= DMX_TS_PES_OTHER ||
141 			    !demux->pesfilter[dvbdmxfeed->pes_type])
142 				return -EINVAL;
143 
144 			demux->pids[dvbdmxfeed->pes_type] |= 0x8000;
145 			demux->pesfilter[dvbdmxfeed->pes_type] = NULL;
146 		}
147 
148 		if (!(dvbdmxfeed->ts_type & TS_DECODER &&
149 		      dvbdmxfeed->pes_type < DMX_TS_PES_OTHER))
150 			return 0;
151 	}
152 
153 	if (mutex_lock_interruptible(&fdtv->demux_mutex))
154 		return -EINTR;
155 
156 	c = (unsigned long)dvbdmxfeed->priv;
157 	dealloc_channel(fdtv, c);
158 	collect_channels(fdtv, &pidc, pids);
159 
160 	ret = avc_tuner_set_pids(fdtv, pidc, pids);
161 
162 	mutex_unlock(&fdtv->demux_mutex);
163 
164 	return ret;
165 }
166 
167 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
168 
fdtv_dvb_register(struct firedtv * fdtv)169 int fdtv_dvb_register(struct firedtv *fdtv)
170 {
171 	int err;
172 
173 	err = dvb_register_adapter(&fdtv->adapter, fdtv_model_names[fdtv->type],
174 				   THIS_MODULE, fdtv->device, adapter_nr);
175 	if (err < 0)
176 		goto fail_log;
177 
178 	/*DMX_TS_FILTERING | DMX_SECTION_FILTERING*/
179 	fdtv->demux.dmx.capabilities = 0;
180 
181 	fdtv->demux.priv	= fdtv;
182 	fdtv->demux.filternum	= 16;
183 	fdtv->demux.feednum	= 16;
184 	fdtv->demux.start_feed	= fdtv_start_feed;
185 	fdtv->demux.stop_feed	= fdtv_stop_feed;
186 	fdtv->demux.write_to_decoder = NULL;
187 
188 	err = dvb_dmx_init(&fdtv->demux);
189 	if (err)
190 		goto fail_unreg_adapter;
191 
192 	fdtv->dmxdev.filternum    = 16;
193 	fdtv->dmxdev.demux        = &fdtv->demux.dmx;
194 	fdtv->dmxdev.capabilities = 0;
195 
196 	err = dvb_dmxdev_init(&fdtv->dmxdev, &fdtv->adapter);
197 	if (err)
198 		goto fail_dmx_release;
199 
200 	fdtv->frontend.source = DMX_FRONTEND_0;
201 
202 	err = fdtv->demux.dmx.add_frontend(&fdtv->demux.dmx, &fdtv->frontend);
203 	if (err)
204 		goto fail_dmxdev_release;
205 
206 	err = fdtv->demux.dmx.connect_frontend(&fdtv->demux.dmx,
207 					       &fdtv->frontend);
208 	if (err)
209 		goto fail_rem_frontend;
210 
211 	dvb_net_init(&fdtv->adapter, &fdtv->dvbnet, &fdtv->demux.dmx);
212 
213 	fdtv_frontend_init(fdtv);
214 	err = dvb_register_frontend(&fdtv->adapter, &fdtv->fe);
215 	if (err)
216 		goto fail_net_release;
217 
218 	err = fdtv_ca_register(fdtv);
219 	if (err)
220 		dev_info(fdtv->device,
221 			 "Conditional Access Module not enabled\n");
222 	return 0;
223 
224 fail_net_release:
225 	dvb_net_release(&fdtv->dvbnet);
226 	fdtv->demux.dmx.close(&fdtv->demux.dmx);
227 fail_rem_frontend:
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:
236 	dev_err(fdtv->device, "DVB initialization failed\n");
237 	return err;
238 }
239 
fdtv_dvb_unregister(struct firedtv * fdtv)240 void fdtv_dvb_unregister(struct firedtv *fdtv)
241 {
242 	fdtv_ca_release(fdtv);
243 	dvb_unregister_frontend(&fdtv->fe);
244 	dvb_net_release(&fdtv->dvbnet);
245 	fdtv->demux.dmx.close(&fdtv->demux.dmx);
246 	fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend);
247 	dvb_dmxdev_release(&fdtv->dmxdev);
248 	dvb_dmx_release(&fdtv->demux);
249 	dvb_unregister_adapter(&fdtv->adapter);
250 }
251 
252 const char *fdtv_model_names[] = {
253 	[FIREDTV_UNKNOWN] = "unknown type",
254 	[FIREDTV_DVB_S]   = "FireDTV S/CI",
255 	[FIREDTV_DVB_C]   = "FireDTV C/CI",
256 	[FIREDTV_DVB_T]   = "FireDTV T/CI",
257 	[FIREDTV_DVB_S2]  = "FireDTV S2  ",
258 };
259 
fdtv_alloc(struct device * dev,const struct firedtv_backend * backend,const char * name,size_t name_len)260 struct firedtv *fdtv_alloc(struct device *dev,
261 			   const struct firedtv_backend *backend,
262 			   const char *name, size_t name_len)
263 {
264 	struct firedtv *fdtv;
265 	int i;
266 
267 	fdtv = kzalloc(sizeof(*fdtv), GFP_KERNEL);
268 	if (!fdtv)
269 		return NULL;
270 
271 	dev->driver_data	= fdtv;
272 	fdtv->device		= dev;
273 	fdtv->isochannel	= -1;
274 	fdtv->voltage		= 0xff;
275 	fdtv->tone		= 0xff;
276 	fdtv->backend		= backend;
277 
278 	mutex_init(&fdtv->avc_mutex);
279 	init_waitqueue_head(&fdtv->avc_wait);
280 	fdtv->avc_reply_received = true;
281 	mutex_init(&fdtv->demux_mutex);
282 	INIT_WORK(&fdtv->remote_ctrl_work, avc_remote_ctrl_work);
283 
284 	for (i = ARRAY_SIZE(fdtv_model_names); --i; )
285 		if (strlen(fdtv_model_names[i]) <= name_len &&
286 		    strncmp(name, fdtv_model_names[i], name_len) == 0)
287 			break;
288 	fdtv->type = i;
289 
290 	return fdtv;
291 }
292 
293 #define MATCH_FLAGS (IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID | \
294 		     IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION)
295 
296 #define DIGITAL_EVERYWHERE_OUI	0x001287
297 #define AVC_UNIT_SPEC_ID_ENTRY	0x00a02d
298 #define AVC_SW_VERSION_ENTRY	0x010001
299 
300 static struct ieee1394_device_id fdtv_id_table[] = {
301 	{
302 		/* FloppyDTV S/CI and FloppyDTV S2 */
303 		.match_flags	= MATCH_FLAGS,
304 		.vendor_id	= DIGITAL_EVERYWHERE_OUI,
305 		.model_id	= 0x000024,
306 		.specifier_id	= AVC_UNIT_SPEC_ID_ENTRY,
307 		.version	= AVC_SW_VERSION_ENTRY,
308 	}, {
309 		/* FloppyDTV T/CI */
310 		.match_flags	= MATCH_FLAGS,
311 		.vendor_id	= DIGITAL_EVERYWHERE_OUI,
312 		.model_id	= 0x000025,
313 		.specifier_id	= AVC_UNIT_SPEC_ID_ENTRY,
314 		.version	= AVC_SW_VERSION_ENTRY,
315 	}, {
316 		/* FloppyDTV C/CI */
317 		.match_flags	= MATCH_FLAGS,
318 		.vendor_id	= DIGITAL_EVERYWHERE_OUI,
319 		.model_id	= 0x000026,
320 		.specifier_id	= AVC_UNIT_SPEC_ID_ENTRY,
321 		.version	= AVC_SW_VERSION_ENTRY,
322 	}, {
323 		/* FireDTV S/CI and FloppyDTV S2 */
324 		.match_flags	= MATCH_FLAGS,
325 		.vendor_id	= DIGITAL_EVERYWHERE_OUI,
326 		.model_id	= 0x000034,
327 		.specifier_id	= AVC_UNIT_SPEC_ID_ENTRY,
328 		.version	= AVC_SW_VERSION_ENTRY,
329 	}, {
330 		/* FireDTV T/CI */
331 		.match_flags	= MATCH_FLAGS,
332 		.vendor_id	= DIGITAL_EVERYWHERE_OUI,
333 		.model_id	= 0x000035,
334 		.specifier_id	= AVC_UNIT_SPEC_ID_ENTRY,
335 		.version	= AVC_SW_VERSION_ENTRY,
336 	}, {
337 		/* FireDTV C/CI */
338 		.match_flags	= MATCH_FLAGS,
339 		.vendor_id	= DIGITAL_EVERYWHERE_OUI,
340 		.model_id	= 0x000036,
341 		.specifier_id	= AVC_UNIT_SPEC_ID_ENTRY,
342 		.version	= AVC_SW_VERSION_ENTRY,
343 	}, {}
344 };
345 MODULE_DEVICE_TABLE(ieee1394, fdtv_id_table);
346 
fdtv_init(void)347 static int __init fdtv_init(void)
348 {
349 	return fdtv_1394_init(fdtv_id_table);
350 }
351 
fdtv_exit(void)352 static void __exit fdtv_exit(void)
353 {
354 	fdtv_1394_exit();
355 }
356 
357 module_init(fdtv_init);
358 module_exit(fdtv_exit);
359 
360 MODULE_AUTHOR("Andreas Monitzer <andy@monitzer.com>");
361 MODULE_AUTHOR("Ben Backx <ben@bbackx.com>");
362 MODULE_DESCRIPTION("FireDTV DVB Driver");
363 MODULE_LICENSE("GPL");
364 MODULE_SUPPORTED_DEVICE("FireDTV DVB");
365