aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb/firewire/firedtv-dvb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/dvb/firewire/firedtv-dvb.c')
-rw-r--r--drivers/media/dvb/firewire/firedtv-dvb.c328
1 files changed, 208 insertions, 120 deletions
diff --git a/drivers/media/dvb/firewire/firedtv-dvb.c b/drivers/media/dvb/firewire/firedtv-dvb.c
index 1823058696f2..9d308dd32a5c 100644
--- a/drivers/media/dvb/firewire/firedtv-dvb.c
+++ b/drivers/media/dvb/firewire/firedtv-dvb.c
@@ -10,75 +10,55 @@
10 * the License, or (at your option) any later version. 10 * the License, or (at your option) any later version.
11 */ 11 */
12 12
13#include <linux/bitops.h>
14#include <linux/device.h>
13#include <linux/errno.h> 15#include <linux/errno.h>
14#include <linux/kernel.h> 16#include <linux/kernel.h>
17#include <linux/mod_devicetable.h>
18#include <linux/module.h>
15#include <linux/mutex.h> 19#include <linux/mutex.h>
20#include <linux/slab.h>
21#include <linux/string.h>
16#include <linux/types.h> 22#include <linux/types.h>
23#include <linux/wait.h>
24#include <linux/workqueue.h>
17 25
26#include <dmxdev.h>
18#include <dvb_demux.h> 27#include <dvb_demux.h>
19#include <dvb_frontend.h>
20#include <dvbdev.h> 28#include <dvbdev.h>
29#include <dvb_frontend.h>
21 30
22#include "avc.h"
23#include "firedtv.h" 31#include "firedtv.h"
24#include "firedtv-ci.h"
25
26DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
27 32
28static struct firedtv_channel *fdtv_channel_allocate(struct firedtv *fdtv) 33static int alloc_channel(struct firedtv *fdtv)
29{ 34{
30 struct firedtv_channel *c = NULL; 35 int i;
31 int k;
32 36
33 if (mutex_lock_interruptible(&fdtv->demux_mutex)) 37 for (i = 0; i < 16; i++)
34 return NULL; 38 if (!__test_and_set_bit(i, &fdtv->channel_active))
35
36 for (k = 0; k < 16; k++)
37 if (!fdtv->channel[k].active) {
38 fdtv->channel[k].active = true;
39 c = &fdtv->channel[k];
40 break; 39 break;
41 } 40 return i;
42
43 mutex_unlock(&fdtv->demux_mutex);
44 return c;
45} 41}
46 42
47static int fdtv_channel_collect(struct firedtv *fdtv, int *pidc, u16 pid[]) 43static void collect_channels(struct firedtv *fdtv, int *pidc, u16 pid[])
48{ 44{
49 int k, l = 0; 45 int i, n;
50
51 if (mutex_lock_interruptible(&fdtv->demux_mutex))
52 return -EINTR;
53
54 for (k = 0; k < 16; k++)
55 if (fdtv->channel[k].active)
56 pid[l++] = fdtv->channel[k].pid;
57
58 mutex_unlock(&fdtv->demux_mutex);
59 46
60 *pidc = l; 47 for (i = 0, n = 0; i < 16; i++)
61 48 if (test_bit(i, &fdtv->channel_active))
62 return 0; 49 pid[n++] = fdtv->channel_pid[i];
50 *pidc = n;
63} 51}
64 52
65static int fdtv_channel_release(struct firedtv *fdtv, 53static inline void dealloc_channel(struct firedtv *fdtv, int i)
66 struct firedtv_channel *channel)
67{ 54{
68 if (mutex_lock_interruptible(&fdtv->demux_mutex)) 55 __clear_bit(i, &fdtv->channel_active);
69 return -EINTR;
70
71 channel->active = false;
72
73 mutex_unlock(&fdtv->demux_mutex);
74 return 0;
75} 56}
76 57
77int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed) 58int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed)
78{ 59{
79 struct firedtv *fdtv = (struct firedtv*)dvbdmxfeed->demux->priv; 60 struct firedtv *fdtv = dvbdmxfeed->demux->priv;
80 struct firedtv_channel *channel; 61 int pidc, c, ret;
81 int pidc,k;
82 u16 pids[16]; 62 u16 pids[16];
83 63
84 switch (dvbdmxfeed->type) { 64 switch (dvbdmxfeed->type) {
@@ -86,11 +66,14 @@ int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed)
86 case DMX_TYPE_SEC: 66 case DMX_TYPE_SEC:
87 break; 67 break;
88 default: 68 default:
89 printk(KERN_ERR "%s: invalid type %u\n", 69 dev_err(fdtv->device, "can't start dmx feed: invalid type %u\n",
90 __func__, dvbdmxfeed->type); 70 dvbdmxfeed->type);
91 return -EINVAL; 71 return -EINVAL;
92 } 72 }
93 73
74 if (mutex_lock_interruptible(&fdtv->demux_mutex))
75 return -EINTR;
76
94 if (dvbdmxfeed->type == DMX_TYPE_TS) { 77 if (dvbdmxfeed->type == DMX_TYPE_TS) {
95 switch (dvbdmxfeed->pes_type) { 78 switch (dvbdmxfeed->pes_type) {
96 case DMX_TS_PES_VIDEO: 79 case DMX_TS_PES_VIDEO:
@@ -98,75 +81,64 @@ int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed)
98 case DMX_TS_PES_TELETEXT: 81 case DMX_TS_PES_TELETEXT:
99 case DMX_TS_PES_PCR: 82 case DMX_TS_PES_PCR:
100 case DMX_TS_PES_OTHER: 83 case DMX_TS_PES_OTHER:
101 //Dirty fix to keep fdtv->channel pid-list up to date 84 c = alloc_channel(fdtv);
102 for(k=0;k<16;k++){
103 if (!fdtv->channel[k].active)
104 fdtv->channel[k].pid =
105 dvbdmxfeed->pid;
106 break;
107 }
108 channel = fdtv_channel_allocate(fdtv);
109 break; 85 break;
110 default: 86 default:
111 printk(KERN_ERR "%s: invalid pes type %u\n", 87 dev_err(fdtv->device,
112 __func__, dvbdmxfeed->pes_type); 88 "can't start dmx feed: invalid pes type %u\n",
113 return -EINVAL; 89 dvbdmxfeed->pes_type);
90 ret = -EINVAL;
91 goto out;
114 } 92 }
115 } else { 93 } else {
116 channel = fdtv_channel_allocate(fdtv); 94 c = alloc_channel(fdtv);
117 } 95 }
118 96
119 if (!channel) { 97 if (c > 15) {
120 printk(KERN_ERR "%s: busy!\n", __func__); 98 dev_err(fdtv->device, "can't start dmx feed: busy\n");
121 return -EBUSY; 99 ret = -EBUSY;
100 goto out;
122 } 101 }
123 102
124 dvbdmxfeed->priv = channel; 103 dvbdmxfeed->priv = (typeof(dvbdmxfeed->priv))(unsigned long)c;
125 channel->pid = dvbdmxfeed->pid; 104 fdtv->channel_pid[c] = dvbdmxfeed->pid;
126 105 collect_channels(fdtv, &pidc, pids);
127 if (fdtv_channel_collect(fdtv, &pidc, pids)) {
128 fdtv_channel_release(fdtv, channel);
129 printk(KERN_ERR "%s: could not collect pids!\n", __func__);
130 return -EINTR;
131 }
132 106
133 if (dvbdmxfeed->pid == 8192) { 107 if (dvbdmxfeed->pid == 8192) {
134 k = avc_tuner_get_ts(fdtv); 108 ret = avc_tuner_get_ts(fdtv);
135 if (k) { 109 if (ret) {
136 fdtv_channel_release(fdtv, channel); 110 dealloc_channel(fdtv, c);
137 printk("%s: AVCTuner_GetTS failed with error %d\n", 111 dev_err(fdtv->device, "can't get TS\n");
138 __func__, k); 112 goto out;
139 return k;
140 } 113 }
141 } else { 114 } else {
142 k = avc_tuner_set_pids(fdtv, pidc, pids); 115 ret = avc_tuner_set_pids(fdtv, pidc, pids);
143 if (k) { 116 if (ret) {
144 fdtv_channel_release(fdtv, channel); 117 dealloc_channel(fdtv, c);
145 printk("%s: AVCTuner_SetPIDs failed with error %d\n", 118 dev_err(fdtv->device, "can't set PIDs\n");
146 __func__, k); 119 goto out;
147 return k;
148 } 120 }
149 } 121 }
122out:
123 mutex_unlock(&fdtv->demux_mutex);
150 124
151 return 0; 125 return ret;
152} 126}
153 127
154int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed) 128int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
155{ 129{
156 struct dvb_demux *demux = dvbdmxfeed->demux; 130 struct dvb_demux *demux = dvbdmxfeed->demux;
157 struct firedtv *fdtv = (struct firedtv*)demux->priv; 131 struct firedtv *fdtv = demux->priv;
158 struct firedtv_channel *c = dvbdmxfeed->priv; 132 int pidc, c, ret;
159 int k, l;
160 u16 pids[16]; 133 u16 pids[16];
161 134
162 if (dvbdmxfeed->type == DMX_TYPE_TS && !((dvbdmxfeed->ts_type & TS_PACKET) && 135 if (dvbdmxfeed->type == DMX_TYPE_TS &&
163 (demux->dmx.frontend->source != DMX_MEMORY_FE))) { 136 !((dvbdmxfeed->ts_type & TS_PACKET) &&
137 (demux->dmx.frontend->source != DMX_MEMORY_FE))) {
164 138
165 if (dvbdmxfeed->ts_type & TS_DECODER) { 139 if (dvbdmxfeed->ts_type & TS_DECODER) {
166
167 if (dvbdmxfeed->pes_type >= DMX_TS_PES_OTHER || 140 if (dvbdmxfeed->pes_type >= DMX_TS_PES_OTHER ||
168 !demux->pesfilter[dvbdmxfeed->pes_type]) 141 !demux->pesfilter[dvbdmxfeed->pes_type])
169
170 return -EINVAL; 142 return -EINVAL;
171 143
172 demux->pids[dvbdmxfeed->pes_type] |= 0x8000; 144 demux->pids[dvbdmxfeed->pes_type] |= 0x8000;
@@ -174,38 +146,32 @@ int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
174 } 146 }
175 147
176 if (!(dvbdmxfeed->ts_type & TS_DECODER && 148 if (!(dvbdmxfeed->ts_type & TS_DECODER &&
177 dvbdmxfeed->pes_type < DMX_TS_PES_OTHER)) 149 dvbdmxfeed->pes_type < DMX_TS_PES_OTHER))
178
179 return 0; 150 return 0;
180 } 151 }
181 152
182 if (mutex_lock_interruptible(&fdtv->demux_mutex)) 153 if (mutex_lock_interruptible(&fdtv->demux_mutex))
183 return -EINTR; 154 return -EINTR;
184 155
185 /* list except channel to be removed */ 156 c = (unsigned long)dvbdmxfeed->priv;
186 for (k = 0, l = 0; k < 16; k++) 157 dealloc_channel(fdtv, c);
187 if (fdtv->channel[k].active) { 158 collect_channels(fdtv, &pidc, pids);
188 if (&fdtv->channel[k] != c)
189 pids[l++] = fdtv->channel[k].pid;
190 else
191 fdtv->channel[k].active = false;
192 }
193 159
194 k = avc_tuner_set_pids(fdtv, l, pids); 160 ret = avc_tuner_set_pids(fdtv, pidc, pids);
195 if (!k)
196 c->active = false;
197 161
198 mutex_unlock(&fdtv->demux_mutex); 162 mutex_unlock(&fdtv->demux_mutex);
199 return k; 163
164 return ret;
200} 165}
201 166
202int fdtv_dvbdev_init(struct firedtv *fdtv, struct device *dev) 167DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
168
169int fdtv_dvb_register(struct firedtv *fdtv)
203{ 170{
204 int err; 171 int err;
205 172
206 err = DVB_REGISTER_ADAPTER(&fdtv->adapter, 173 err = dvb_register_adapter(&fdtv->adapter, fdtv_model_names[fdtv->type],
207 fdtv_model_names[fdtv->type], 174 THIS_MODULE, fdtv->device, adapter_nr);
208 THIS_MODULE, dev, adapter_nr);
209 if (err < 0) 175 if (err < 0)
210 goto fail_log; 176 goto fail_log;
211 177
@@ -223,9 +189,9 @@ int fdtv_dvbdev_init(struct firedtv *fdtv, struct device *dev)
223 if (err) 189 if (err)
224 goto fail_unreg_adapter; 190 goto fail_unreg_adapter;
225 191
226 fdtv->dmxdev.filternum = 16; 192 fdtv->dmxdev.filternum = 16;
227 fdtv->dmxdev.demux = &fdtv->demux.dmx; 193 fdtv->dmxdev.demux = &fdtv->demux.dmx;
228 fdtv->dmxdev.capabilities = 0; 194 fdtv->dmxdev.capabilities = 0;
229 195
230 err = dvb_dmxdev_init(&fdtv->dmxdev, &fdtv->adapter); 196 err = dvb_dmxdev_init(&fdtv->dmxdev, &fdtv->adapter);
231 if (err) 197 if (err)
@@ -233,13 +199,12 @@ int fdtv_dvbdev_init(struct firedtv *fdtv, struct device *dev)
233 199
234 fdtv->frontend.source = DMX_FRONTEND_0; 200 fdtv->frontend.source = DMX_FRONTEND_0;
235 201
236 err = fdtv->demux.dmx.add_frontend(&fdtv->demux.dmx, 202 err = fdtv->demux.dmx.add_frontend(&fdtv->demux.dmx, &fdtv->frontend);
237 &fdtv->frontend);
238 if (err) 203 if (err)
239 goto fail_dmxdev_release; 204 goto fail_dmxdev_release;
240 205
241 err = fdtv->demux.dmx.connect_frontend(&fdtv->demux.dmx, 206 err = fdtv->demux.dmx.connect_frontend(&fdtv->demux.dmx,
242 &fdtv->frontend); 207 &fdtv->frontend);
243 if (err) 208 if (err)
244 goto fail_rem_frontend; 209 goto fail_rem_frontend;
245 210
@@ -252,16 +217,15 @@ int fdtv_dvbdev_init(struct firedtv *fdtv, struct device *dev)
252 217
253 err = fdtv_ca_register(fdtv); 218 err = fdtv_ca_register(fdtv);
254 if (err) 219 if (err)
255 dev_info(dev, "Conditional Access Module not enabled\n"); 220 dev_info(fdtv->device,
256 221 "Conditional Access Module not enabled\n");
257 return 0; 222 return 0;
258 223
259fail_net_release: 224fail_net_release:
260 dvb_net_release(&fdtv->dvbnet); 225 dvb_net_release(&fdtv->dvbnet);
261 fdtv->demux.dmx.close(&fdtv->demux.dmx); 226 fdtv->demux.dmx.close(&fdtv->demux.dmx);
262fail_rem_frontend: 227fail_rem_frontend:
263 fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, 228 fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend);
264 &fdtv->frontend);
265fail_dmxdev_release: 229fail_dmxdev_release:
266 dvb_dmxdev_release(&fdtv->dmxdev); 230 dvb_dmxdev_release(&fdtv->dmxdev);
267fail_dmx_release: 231fail_dmx_release:
@@ -269,8 +233,132 @@ fail_dmx_release:
269fail_unreg_adapter: 233fail_unreg_adapter:
270 dvb_unregister_adapter(&fdtv->adapter); 234 dvb_unregister_adapter(&fdtv->adapter);
271fail_log: 235fail_log:
272 dev_err(dev, "DVB initialization failed\n"); 236 dev_err(fdtv->device, "DVB initialization failed\n");
273 return err; 237 return err;
274} 238}
275 239
240void 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
252const 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
260struct 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
300static 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};
345MODULE_DEVICE_TABLE(ieee1394, fdtv_id_table);
346
347static int __init fdtv_init(void)
348{
349 return fdtv_1394_init(fdtv_id_table);
350}
351
352static void __exit fdtv_exit(void)
353{
354 fdtv_1394_exit();
355}
356
357module_init(fdtv_init);
358module_exit(fdtv_exit);
276 359
360MODULE_AUTHOR("Andreas Monitzer <andy@monitzer.com>");
361MODULE_AUTHOR("Ben Backx <ben@bbackx.com>");
362MODULE_DESCRIPTION("FireDTV DVB Driver");
363MODULE_LICENSE("GPL");
364MODULE_SUPPORTED_DEVICE("FireDTV DVB");