Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/media/dvb/firewire/firedtv-dvb.c
15112 views
1
/*
2
* FireDTV driver (formerly known as FireSAT)
3
*
4
* Copyright (C) 2004 Andreas Monitzer <[email protected]>
5
* Copyright (C) 2008 Henrik Kurelid <[email protected]>
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/module.h>
18
#include <linux/mutex.h>
19
#include <linux/types.h>
20
21
#include <dmxdev.h>
22
#include <dvb_demux.h>
23
#include <dvbdev.h>
24
#include <dvb_frontend.h>
25
26
#include "firedtv.h"
27
28
static int alloc_channel(struct firedtv *fdtv)
29
{
30
int i;
31
32
for (i = 0; i < 16; i++)
33
if (!__test_and_set_bit(i, &fdtv->channel_active))
34
break;
35
return i;
36
}
37
38
static void collect_channels(struct firedtv *fdtv, int *pidc, u16 pid[])
39
{
40
int i, n;
41
42
for (i = 0, n = 0; i < 16; i++)
43
if (test_bit(i, &fdtv->channel_active))
44
pid[n++] = fdtv->channel_pid[i];
45
*pidc = n;
46
}
47
48
static inline void dealloc_channel(struct firedtv *fdtv, int i)
49
{
50
__clear_bit(i, &fdtv->channel_active);
51
}
52
53
int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed)
54
{
55
struct firedtv *fdtv = dvbdmxfeed->demux->priv;
56
int pidc, c, ret;
57
u16 pids[16];
58
59
switch (dvbdmxfeed->type) {
60
case DMX_TYPE_TS:
61
case DMX_TYPE_SEC:
62
break;
63
default:
64
dev_err(fdtv->device, "can't start dmx feed: invalid type %u\n",
65
dvbdmxfeed->type);
66
return -EINVAL;
67
}
68
69
if (mutex_lock_interruptible(&fdtv->demux_mutex))
70
return -EINTR;
71
72
if (dvbdmxfeed->type == DMX_TYPE_TS) {
73
switch (dvbdmxfeed->pes_type) {
74
case DMX_TS_PES_VIDEO:
75
case DMX_TS_PES_AUDIO:
76
case DMX_TS_PES_TELETEXT:
77
case DMX_TS_PES_PCR:
78
case DMX_TS_PES_OTHER:
79
c = alloc_channel(fdtv);
80
break;
81
default:
82
dev_err(fdtv->device,
83
"can't start dmx feed: invalid pes type %u\n",
84
dvbdmxfeed->pes_type);
85
ret = -EINVAL;
86
goto out;
87
}
88
} else {
89
c = alloc_channel(fdtv);
90
}
91
92
if (c > 15) {
93
dev_err(fdtv->device, "can't start dmx feed: busy\n");
94
ret = -EBUSY;
95
goto out;
96
}
97
98
dvbdmxfeed->priv = (typeof(dvbdmxfeed->priv))(unsigned long)c;
99
fdtv->channel_pid[c] = dvbdmxfeed->pid;
100
collect_channels(fdtv, &pidc, pids);
101
102
if (dvbdmxfeed->pid == 8192) {
103
ret = avc_tuner_get_ts(fdtv);
104
if (ret) {
105
dealloc_channel(fdtv, c);
106
dev_err(fdtv->device, "can't get TS\n");
107
goto out;
108
}
109
} else {
110
ret = avc_tuner_set_pids(fdtv, pidc, pids);
111
if (ret) {
112
dealloc_channel(fdtv, c);
113
dev_err(fdtv->device, "can't set PIDs\n");
114
goto out;
115
}
116
}
117
out:
118
mutex_unlock(&fdtv->demux_mutex);
119
120
return ret;
121
}
122
123
int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
124
{
125
struct dvb_demux *demux = dvbdmxfeed->demux;
126
struct firedtv *fdtv = demux->priv;
127
int pidc, c, ret;
128
u16 pids[16];
129
130
if (dvbdmxfeed->type == DMX_TYPE_TS &&
131
!((dvbdmxfeed->ts_type & TS_PACKET) &&
132
(demux->dmx.frontend->source != DMX_MEMORY_FE))) {
133
134
if (dvbdmxfeed->ts_type & TS_DECODER) {
135
if (dvbdmxfeed->pes_type >= DMX_TS_PES_OTHER ||
136
!demux->pesfilter[dvbdmxfeed->pes_type])
137
return -EINVAL;
138
139
demux->pids[dvbdmxfeed->pes_type] |= 0x8000;
140
demux->pesfilter[dvbdmxfeed->pes_type] = NULL;
141
}
142
143
if (!(dvbdmxfeed->ts_type & TS_DECODER &&
144
dvbdmxfeed->pes_type < DMX_TS_PES_OTHER))
145
return 0;
146
}
147
148
if (mutex_lock_interruptible(&fdtv->demux_mutex))
149
return -EINTR;
150
151
c = (unsigned long)dvbdmxfeed->priv;
152
dealloc_channel(fdtv, c);
153
collect_channels(fdtv, &pidc, pids);
154
155
ret = avc_tuner_set_pids(fdtv, pidc, pids);
156
157
mutex_unlock(&fdtv->demux_mutex);
158
159
return ret;
160
}
161
162
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
163
164
int fdtv_dvb_register(struct firedtv *fdtv, const char *name)
165
{
166
int err;
167
168
err = dvb_register_adapter(&fdtv->adapter, name,
169
THIS_MODULE, fdtv->device, adapter_nr);
170
if (err < 0)
171
goto fail_log;
172
173
/*DMX_TS_FILTERING | DMX_SECTION_FILTERING*/
174
fdtv->demux.dmx.capabilities = 0;
175
176
fdtv->demux.priv = fdtv;
177
fdtv->demux.filternum = 16;
178
fdtv->demux.feednum = 16;
179
fdtv->demux.start_feed = fdtv_start_feed;
180
fdtv->demux.stop_feed = fdtv_stop_feed;
181
fdtv->demux.write_to_decoder = NULL;
182
183
err = dvb_dmx_init(&fdtv->demux);
184
if (err)
185
goto fail_unreg_adapter;
186
187
fdtv->dmxdev.filternum = 16;
188
fdtv->dmxdev.demux = &fdtv->demux.dmx;
189
fdtv->dmxdev.capabilities = 0;
190
191
err = dvb_dmxdev_init(&fdtv->dmxdev, &fdtv->adapter);
192
if (err)
193
goto fail_dmx_release;
194
195
fdtv->frontend.source = DMX_FRONTEND_0;
196
197
err = fdtv->demux.dmx.add_frontend(&fdtv->demux.dmx, &fdtv->frontend);
198
if (err)
199
goto fail_dmxdev_release;
200
201
err = fdtv->demux.dmx.connect_frontend(&fdtv->demux.dmx,
202
&fdtv->frontend);
203
if (err)
204
goto fail_rem_frontend;
205
206
dvb_net_init(&fdtv->adapter, &fdtv->dvbnet, &fdtv->demux.dmx);
207
208
fdtv_frontend_init(fdtv, name);
209
err = dvb_register_frontend(&fdtv->adapter, &fdtv->fe);
210
if (err)
211
goto fail_net_release;
212
213
err = fdtv_ca_register(fdtv);
214
if (err)
215
dev_info(fdtv->device,
216
"Conditional Access Module not enabled\n");
217
return 0;
218
219
fail_net_release:
220
dvb_net_release(&fdtv->dvbnet);
221
fdtv->demux.dmx.close(&fdtv->demux.dmx);
222
fail_rem_frontend:
223
fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend);
224
fail_dmxdev_release:
225
dvb_dmxdev_release(&fdtv->dmxdev);
226
fail_dmx_release:
227
dvb_dmx_release(&fdtv->demux);
228
fail_unreg_adapter:
229
dvb_unregister_adapter(&fdtv->adapter);
230
fail_log:
231
dev_err(fdtv->device, "DVB initialization failed\n");
232
return err;
233
}
234
235
void fdtv_dvb_unregister(struct firedtv *fdtv)
236
{
237
fdtv_ca_release(fdtv);
238
dvb_unregister_frontend(&fdtv->fe);
239
dvb_net_release(&fdtv->dvbnet);
240
fdtv->demux.dmx.close(&fdtv->demux.dmx);
241
fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend);
242
dvb_dmxdev_release(&fdtv->dmxdev);
243
dvb_dmx_release(&fdtv->demux);
244
dvb_unregister_adapter(&fdtv->adapter);
245
}
246
247