1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * FireDTV driver (formerly known as FireSAT)
5 * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
6 * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
9 #include <linux/bitops.h>
10 #include <linux/device.h>
11 #include <linux/errno.h>
12 #include <linux/kernel.h>
13 #include <linux/module.h>
14 #include <linux/mutex.h>
15 #include <linux/types.h>
17 #include <media/dmxdev.h>
18 #include <media/dvb_demux.h>
19 #include <media/dvbdev.h>
20 #include <media/dvb_frontend.h>
24 static int alloc_channel(struct firedtv
*fdtv
)
28 for (i
= 0; i
< 16; i
++)
29 if (!__test_and_set_bit(i
, &fdtv
->channel_active
))
34 static void collect_channels(struct firedtv
*fdtv
, int *pidc
, u16 pid
[])
38 for (i
= 0, n
= 0; i
< 16; i
++)
39 if (test_bit(i
, &fdtv
->channel_active
))
40 pid
[n
++] = fdtv
->channel_pid
[i
];
44 static inline void dealloc_channel(struct firedtv
*fdtv
, int i
)
46 __clear_bit(i
, &fdtv
->channel_active
);
49 int fdtv_start_feed(struct dvb_demux_feed
*dvbdmxfeed
)
51 struct firedtv
*fdtv
= dvbdmxfeed
->demux
->priv
;
55 switch (dvbdmxfeed
->type
) {
60 dev_err(fdtv
->device
, "can't start dmx feed: invalid type %u\n",
65 if (mutex_lock_interruptible(&fdtv
->demux_mutex
))
68 if (dvbdmxfeed
->type
== DMX_TYPE_TS
) {
69 switch (dvbdmxfeed
->pes_type
) {
72 case DMX_PES_TELETEXT
:
75 c
= alloc_channel(fdtv
);
79 "can't start dmx feed: invalid pes type %u\n",
80 dvbdmxfeed
->pes_type
);
85 c
= alloc_channel(fdtv
);
89 dev_err(fdtv
->device
, "can't start dmx feed: busy\n");
94 dvbdmxfeed
->priv
= (typeof(dvbdmxfeed
->priv
))(unsigned long)c
;
95 fdtv
->channel_pid
[c
] = dvbdmxfeed
->pid
;
96 collect_channels(fdtv
, &pidc
, pids
);
98 if (dvbdmxfeed
->pid
== 8192) {
99 ret
= avc_tuner_get_ts(fdtv
);
101 dealloc_channel(fdtv
, c
);
102 dev_err(fdtv
->device
, "can't get TS\n");
106 ret
= avc_tuner_set_pids(fdtv
, pidc
, pids
);
108 dealloc_channel(fdtv
, c
);
109 dev_err(fdtv
->device
, "can't set PIDs\n");
114 mutex_unlock(&fdtv
->demux_mutex
);
119 int fdtv_stop_feed(struct dvb_demux_feed
*dvbdmxfeed
)
121 struct dvb_demux
*demux
= dvbdmxfeed
->demux
;
122 struct firedtv
*fdtv
= demux
->priv
;
126 if (dvbdmxfeed
->type
== DMX_TYPE_TS
&&
127 !((dvbdmxfeed
->ts_type
& TS_PACKET
) &&
128 (demux
->dmx
.frontend
->source
!= DMX_MEMORY_FE
))) {
130 if (dvbdmxfeed
->ts_type
& TS_DECODER
) {
131 if (dvbdmxfeed
->pes_type
>= DMX_PES_OTHER
||
132 !demux
->pesfilter
[dvbdmxfeed
->pes_type
])
135 demux
->pids
[dvbdmxfeed
->pes_type
] |= 0x8000;
136 demux
->pesfilter
[dvbdmxfeed
->pes_type
] = NULL
;
139 if (!(dvbdmxfeed
->ts_type
& TS_DECODER
&&
140 dvbdmxfeed
->pes_type
< DMX_PES_OTHER
))
144 if (mutex_lock_interruptible(&fdtv
->demux_mutex
))
147 c
= (unsigned long)dvbdmxfeed
->priv
;
148 dealloc_channel(fdtv
, c
);
149 collect_channels(fdtv
, &pidc
, pids
);
151 ret
= avc_tuner_set_pids(fdtv
, pidc
, pids
);
153 mutex_unlock(&fdtv
->demux_mutex
);
158 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr
);
160 int fdtv_dvb_register(struct firedtv
*fdtv
, const char *name
)
164 err
= dvb_register_adapter(&fdtv
->adapter
, name
,
165 THIS_MODULE
, fdtv
->device
, adapter_nr
);
169 /*DMX_TS_FILTERING | DMX_SECTION_FILTERING*/
170 fdtv
->demux
.dmx
.capabilities
= 0;
172 fdtv
->demux
.priv
= fdtv
;
173 fdtv
->demux
.filternum
= 16;
174 fdtv
->demux
.feednum
= 16;
175 fdtv
->demux
.start_feed
= fdtv_start_feed
;
176 fdtv
->demux
.stop_feed
= fdtv_stop_feed
;
177 fdtv
->demux
.write_to_decoder
= NULL
;
179 err
= dvb_dmx_init(&fdtv
->demux
);
181 goto fail_unreg_adapter
;
183 fdtv
->dmxdev
.filternum
= 16;
184 fdtv
->dmxdev
.demux
= &fdtv
->demux
.dmx
;
185 fdtv
->dmxdev
.capabilities
= 0;
187 err
= dvb_dmxdev_init(&fdtv
->dmxdev
, &fdtv
->adapter
);
189 goto fail_dmx_release
;
191 fdtv
->frontend
.source
= DMX_FRONTEND_0
;
193 err
= fdtv
->demux
.dmx
.add_frontend(&fdtv
->demux
.dmx
, &fdtv
->frontend
);
195 goto fail_dmxdev_release
;
197 err
= fdtv
->demux
.dmx
.connect_frontend(&fdtv
->demux
.dmx
,
200 goto fail_rem_frontend
;
202 err
= dvb_net_init(&fdtv
->adapter
, &fdtv
->dvbnet
, &fdtv
->demux
.dmx
);
204 goto fail_disconnect_frontend
;
206 fdtv_frontend_init(fdtv
, name
);
207 err
= dvb_register_frontend(&fdtv
->adapter
, &fdtv
->fe
);
209 goto fail_net_release
;
211 err
= fdtv_ca_register(fdtv
);
213 dev_info(fdtv
->device
,
214 "Conditional Access Module not enabled\n");
218 dvb_net_release(&fdtv
->dvbnet
);
219 fail_disconnect_frontend
:
220 fdtv
->demux
.dmx
.close(&fdtv
->demux
.dmx
);
222 fdtv
->demux
.dmx
.remove_frontend(&fdtv
->demux
.dmx
, &fdtv
->frontend
);
224 dvb_dmxdev_release(&fdtv
->dmxdev
);
226 dvb_dmx_release(&fdtv
->demux
);
228 dvb_unregister_adapter(&fdtv
->adapter
);
230 dev_err(fdtv
->device
, "DVB initialization failed\n");
234 void fdtv_dvb_unregister(struct firedtv
*fdtv
)
236 fdtv_ca_release(fdtv
);
237 dvb_unregister_frontend(&fdtv
->fe
);
238 dvb_net_release(&fdtv
->dvbnet
);
239 fdtv
->demux
.dmx
.close(&fdtv
->demux
.dmx
);
240 fdtv
->demux
.dmx
.remove_frontend(&fdtv
->demux
.dmx
, &fdtv
->frontend
);
241 dvb_dmxdev_release(&fdtv
->dmxdev
);
242 dvb_dmx_release(&fdtv
->demux
);
243 dvb_unregister_adapter(&fdtv
->adapter
);