Merge ath-next from ath.git
[deliverable/linux.git] / drivers / media / firewire / firedtv-dvb.c
CommitLineData
df4846c3 1/*
612262a5 2 * FireDTV driver (formerly known as FireSAT)
df4846c3 3 *
612262a5
SR
4 * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
5 * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
df4846c3
HK
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
15490795
SR
13#include <linux/bitops.h>
14#include <linux/device.h>
c81c8b68 15#include <linux/errno.h>
612262a5 16#include <linux/kernel.h>
15490795 17#include <linux/module.h>
612262a5
SR
18#include <linux/mutex.h>
19#include <linux/types.h>
20
15490795 21#include <dmxdev.h>
612262a5 22#include <dvb_demux.h>
c81c8b68 23#include <dvbdev.h>
15490795 24#include <dvb_frontend.h>
c81c8b68 25
a70f81c1 26#include "firedtv.h"
c81c8b68 27
15490795 28static int alloc_channel(struct firedtv *fdtv)
c81c8b68 29{
15490795 30 int i;
c81c8b68 31
15490795
SR
32 for (i = 0; i < 16; i++)
33 if (!__test_and_set_bit(i, &fdtv->channel_active))
612262a5 34 break;
15490795 35 return i;
c81c8b68
GKH
36}
37
15490795 38static void collect_channels(struct firedtv *fdtv, int *pidc, u16 pid[])
c81c8b68 39{
15490795 40 int i, n;
c81c8b68 41
15490795
SR
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;
c81c8b68
GKH
46}
47
15490795 48static inline void dealloc_channel(struct firedtv *fdtv, int i)
c81c8b68 49{
15490795 50 __clear_bit(i, &fdtv->channel_active);
c81c8b68
GKH
51}
52
a70f81c1 53int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed)
c81c8b68 54{
15490795
SR
55 struct firedtv *fdtv = dvbdmxfeed->demux->priv;
56 int pidc, c, ret;
c81c8b68
GKH
57 u16 pids[16];
58
c81c8b68
GKH
59 switch (dvbdmxfeed->type) {
60 case DMX_TYPE_TS:
61 case DMX_TYPE_SEC:
62 break;
63 default:
15490795
SR
64 dev_err(fdtv->device, "can't start dmx feed: invalid type %u\n",
65 dvbdmxfeed->type);
c81c8b68
GKH
66 return -EINVAL;
67 }
68
15490795
SR
69 if (mutex_lock_interruptible(&fdtv->demux_mutex))
70 return -EINTR;
71
c81c8b68
GKH
72 if (dvbdmxfeed->type == DMX_TYPE_TS) {
73 switch (dvbdmxfeed->pes_type) {
fde04ab9
MCC
74 case DMX_PES_VIDEO:
75 case DMX_PES_AUDIO:
76 case DMX_PES_TELETEXT:
77 case DMX_PES_PCR:
78 case DMX_PES_OTHER:
15490795 79 c = alloc_channel(fdtv);
c81c8b68
GKH
80 break;
81 default:
15490795
SR
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;
c81c8b68
GKH
87 }
88 } else {
15490795 89 c = alloc_channel(fdtv);
c81c8b68
GKH
90 }
91
15490795
SR
92 if (c > 15) {
93 dev_err(fdtv->device, "can't start dmx feed: busy\n");
94 ret = -EBUSY;
95 goto out;
c81c8b68
GKH
96 }
97
15490795
SR
98 dvbdmxfeed->priv = (typeof(dvbdmxfeed->priv))(unsigned long)c;
99 fdtv->channel_pid[c] = dvbdmxfeed->pid;
100 collect_channels(fdtv, &pidc, pids);
c81c8b68 101
8ae83cdf 102 if (dvbdmxfeed->pid == 8192) {
15490795
SR
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;
c81c8b68 108 }
8ae83cdf 109 } else {
15490795
SR
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;
c81c8b68
GKH
115 }
116 }
15490795
SR
117out:
118 mutex_unlock(&fdtv->demux_mutex);
c81c8b68 119
15490795 120 return ret;
c81c8b68
GKH
121}
122
a70f81c1 123int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
c81c8b68
GKH
124{
125 struct dvb_demux *demux = dvbdmxfeed->demux;
15490795
SR
126 struct firedtv *fdtv = demux->priv;
127 int pidc, c, ret;
c81c8b68
GKH
128 u16 pids[16];
129
15490795
SR
130 if (dvbdmxfeed->type == DMX_TYPE_TS &&
131 !((dvbdmxfeed->ts_type & TS_PACKET) &&
132 (demux->dmx.frontend->source != DMX_MEMORY_FE))) {
c81c8b68
GKH
133
134 if (dvbdmxfeed->ts_type & TS_DECODER) {
fde04ab9 135 if (dvbdmxfeed->pes_type >= DMX_PES_OTHER ||
15490795 136 !demux->pesfilter[dvbdmxfeed->pes_type])
c81c8b68
GKH
137 return -EINVAL;
138
139 demux->pids[dvbdmxfeed->pes_type] |= 0x8000;
8ae83cdf 140 demux->pesfilter[dvbdmxfeed->pes_type] = NULL;
c81c8b68
GKH
141 }
142
143 if (!(dvbdmxfeed->ts_type & TS_DECODER &&
fde04ab9 144 dvbdmxfeed->pes_type < DMX_PES_OTHER))
c81c8b68
GKH
145 return 0;
146 }
147
a70f81c1 148 if (mutex_lock_interruptible(&fdtv->demux_mutex))
c81c8b68
GKH
149 return -EINTR;
150
15490795
SR
151 c = (unsigned long)dvbdmxfeed->priv;
152 dealloc_channel(fdtv, c);
153 collect_channels(fdtv, &pidc, pids);
c81c8b68 154
15490795 155 ret = avc_tuner_set_pids(fdtv, pidc, pids);
c81c8b68 156
a70f81c1 157 mutex_unlock(&fdtv->demux_mutex);
15490795
SR
158
159 return ret;
c81c8b68
GKH
160}
161
15490795
SR
162DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
163
92374e88 164int fdtv_dvb_register(struct firedtv *fdtv, const char *name)
c81c8b68 165{
8ae83cdf 166 int err;
c81c8b68 167
92374e88 168 err = dvb_register_adapter(&fdtv->adapter, name,
15490795 169 THIS_MODULE, fdtv->device, adapter_nr);
a40bf559 170 if (err < 0)
8ae83cdf 171 goto fail_log;
c81c8b68 172
8ae83cdf 173 /*DMX_TS_FILTERING | DMX_SECTION_FILTERING*/
a70f81c1 174 fdtv->demux.dmx.capabilities = 0;
c81c8b68 175
a70f81c1
R
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;
c81c8b68 182
a70f81c1 183 err = dvb_dmx_init(&fdtv->demux);
8ae83cdf
SR
184 if (err)
185 goto fail_unreg_adapter;
c81c8b68 186
15490795
SR
187 fdtv->dmxdev.filternum = 16;
188 fdtv->dmxdev.demux = &fdtv->demux.dmx;
189 fdtv->dmxdev.capabilities = 0;
c81c8b68 190
a70f81c1 191 err = dvb_dmxdev_init(&fdtv->dmxdev, &fdtv->adapter);
8ae83cdf
SR
192 if (err)
193 goto fail_dmx_release;
c81c8b68 194
a70f81c1 195 fdtv->frontend.source = DMX_FRONTEND_0;
c81c8b68 196
15490795 197 err = fdtv->demux.dmx.add_frontend(&fdtv->demux.dmx, &fdtv->frontend);
8ae83cdf
SR
198 if (err)
199 goto fail_dmxdev_release;
c81c8b68 200
a70f81c1 201 err = fdtv->demux.dmx.connect_frontend(&fdtv->demux.dmx,
15490795 202 &fdtv->frontend);
8ae83cdf
SR
203 if (err)
204 goto fail_rem_frontend;
c81c8b68 205
f1d99f39
JN
206 err = dvb_net_init(&fdtv->adapter, &fdtv->dvbnet, &fdtv->demux.dmx);
207 if (err)
208 goto fail_disconnect_frontend;
c81c8b68 209
92374e88 210 fdtv_frontend_init(fdtv, name);
a70f81c1 211 err = dvb_register_frontend(&fdtv->adapter, &fdtv->fe);
8ae83cdf
SR
212 if (err)
213 goto fail_net_release;
c81c8b68 214
a70f81c1 215 err = fdtv_ca_register(fdtv);
8ae83cdf 216 if (err)
15490795
SR
217 dev_info(fdtv->device,
218 "Conditional Access Module not enabled\n");
8ae83cdf 219 return 0;
c81c8b68 220
8ae83cdf 221fail_net_release:
a70f81c1 222 dvb_net_release(&fdtv->dvbnet);
f1d99f39 223fail_disconnect_frontend:
a70f81c1 224 fdtv->demux.dmx.close(&fdtv->demux.dmx);
8ae83cdf 225fail_rem_frontend:
15490795 226 fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend);
8ae83cdf 227fail_dmxdev_release:
a70f81c1 228 dvb_dmxdev_release(&fdtv->dmxdev);
8ae83cdf 229fail_dmx_release:
a70f81c1 230 dvb_dmx_release(&fdtv->demux);
8ae83cdf 231fail_unreg_adapter:
a70f81c1 232 dvb_unregister_adapter(&fdtv->adapter);
8ae83cdf 233fail_log:
15490795 234 dev_err(fdtv->device, "DVB initialization failed\n");
8ae83cdf 235 return err;
c81c8b68 236}
df4846c3 237
15490795
SR
238void fdtv_dvb_unregister(struct firedtv *fdtv)
239{
240 fdtv_ca_release(fdtv);
241 dvb_unregister_frontend(&fdtv->fe);
242 dvb_net_release(&fdtv->dvbnet);
243 fdtv->demux.dmx.close(&fdtv->demux.dmx);
244 fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend);
245 dvb_dmxdev_release(&fdtv->dmxdev);
246 dvb_dmx_release(&fdtv->demux);
247 dvb_unregister_adapter(&fdtv->adapter);
248}
This page took 0.799329 seconds and 5 git commands to generate.