firedtv-dvb.c revision a70f81c1c0dac113ac4705e7701e2676e67905cd
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/errno.h> 14#include <linux/kernel.h> 15#include <linux/mutex.h> 16#include <linux/types.h> 17 18#include <dvb_demux.h> 19#include <dvb_frontend.h> 20#include <dvbdev.h> 21 22#include "avc.h" 23#include "firedtv.h" 24#include "firedtv-ci.h" 25 26DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); 27 28static struct firedtv_channel *fdtv_channel_allocate(struct firedtv *fdtv) 29{ 30 struct firedtv_channel *c = NULL; 31 int k; 32 33 if (mutex_lock_interruptible(&fdtv->demux_mutex)) 34 return NULL; 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; 41 } 42 43 mutex_unlock(&fdtv->demux_mutex); 44 return c; 45} 46 47static int fdtv_channel_collect(struct firedtv *fdtv, int *pidc, u16 pid[]) 48{ 49 int k, l = 0; 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 60 *pidc = l; 61 62 return 0; 63} 64 65static int fdtv_channel_release(struct firedtv *fdtv, 66 struct firedtv_channel *channel) 67{ 68 if (mutex_lock_interruptible(&fdtv->demux_mutex)) 69 return -EINTR; 70 71 channel->active = false; 72 73 mutex_unlock(&fdtv->demux_mutex); 74 return 0; 75} 76 77int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed) 78{ 79 struct firedtv *fdtv = (struct firedtv*)dvbdmxfeed->demux->priv; 80 struct firedtv_channel *channel; 81 int pidc,k; 82 u16 pids[16]; 83 84 switch (dvbdmxfeed->type) { 85 case DMX_TYPE_TS: 86 case DMX_TYPE_SEC: 87 break; 88 default: 89 printk(KERN_ERR "%s: invalid type %u\n", 90 __func__, dvbdmxfeed->type); 91 return -EINVAL; 92 } 93 94 if (dvbdmxfeed->type == DMX_TYPE_TS) { 95 switch (dvbdmxfeed->pes_type) { 96 case DMX_TS_PES_VIDEO: 97 case DMX_TS_PES_AUDIO: 98 case DMX_TS_PES_TELETEXT: 99 case DMX_TS_PES_PCR: 100 case DMX_TS_PES_OTHER: 101 //Dirty fix to keep fdtv->channel pid-list up to date 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; 110 default: 111 printk(KERN_ERR "%s: invalid pes type %u\n", 112 __func__, dvbdmxfeed->pes_type); 113 return -EINVAL; 114 } 115 } else { 116 channel = fdtv_channel_allocate(fdtv); 117 } 118 119 if (!channel) { 120 printk(KERN_ERR "%s: busy!\n", __func__); 121 return -EBUSY; 122 } 123 124 dvbdmxfeed->priv = channel; 125 channel->pid = dvbdmxfeed->pid; 126 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 133 if (dvbdmxfeed->pid == 8192) { 134 k = avc_tuner_get_ts(fdtv); 135 if (k) { 136 fdtv_channel_release(fdtv, channel); 137 printk("%s: AVCTuner_GetTS failed with error %d\n", 138 __func__, k); 139 return k; 140 } 141 } else { 142 k = avc_tuner_set_pids(fdtv, pidc, pids); 143 if (k) { 144 fdtv_channel_release(fdtv, channel); 145 printk("%s: AVCTuner_SetPIDs failed with error %d\n", 146 __func__, k); 147 return k; 148 } 149 } 150 151 return 0; 152} 153 154int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed) 155{ 156 struct dvb_demux *demux = dvbdmxfeed->demux; 157 struct firedtv *fdtv = (struct firedtv*)demux->priv; 158 struct firedtv_channel *c = dvbdmxfeed->priv; 159 int k, l; 160 u16 pids[16]; 161 162 if (dvbdmxfeed->type == DMX_TYPE_TS && !((dvbdmxfeed->ts_type & TS_PACKET) && 163 (demux->dmx.frontend->source != DMX_MEMORY_FE))) { 164 165 if (dvbdmxfeed->ts_type & TS_DECODER) { 166 167 if (dvbdmxfeed->pes_type >= DMX_TS_PES_OTHER || 168 !demux->pesfilter[dvbdmxfeed->pes_type]) 169 170 return -EINVAL; 171 172 demux->pids[dvbdmxfeed->pes_type] |= 0x8000; 173 demux->pesfilter[dvbdmxfeed->pes_type] = NULL; 174 } 175 176 if (!(dvbdmxfeed->ts_type & TS_DECODER && 177 dvbdmxfeed->pes_type < DMX_TS_PES_OTHER)) 178 179 return 0; 180 } 181 182 if (mutex_lock_interruptible(&fdtv->demux_mutex)) 183 return -EINTR; 184 185 /* list except channel to be removed */ 186 for (k = 0, l = 0; k < 16; k++) 187 if (fdtv->channel[k].active) { 188 if (&fdtv->channel[k] != c) 189 pids[l++] = fdtv->channel[k].pid; 190 else 191 fdtv->channel[k].active = false; 192 } 193 194 k = avc_tuner_set_pids(fdtv, l, pids); 195 if (!k) 196 c->active = false; 197 198 mutex_unlock(&fdtv->demux_mutex); 199 return k; 200} 201 202int fdtv_dvbdev_init(struct firedtv *fdtv, struct device *dev) 203{ 204 int err; 205 206 err = DVB_REGISTER_ADAPTER(&fdtv->adapter, 207 fdtv_model_names[fdtv->type], 208 THIS_MODULE, dev, adapter_nr); 209 if (err < 0) 210 goto fail_log; 211 212 /*DMX_TS_FILTERING | DMX_SECTION_FILTERING*/ 213 fdtv->demux.dmx.capabilities = 0; 214 215 fdtv->demux.priv = fdtv; 216 fdtv->demux.filternum = 16; 217 fdtv->demux.feednum = 16; 218 fdtv->demux.start_feed = fdtv_start_feed; 219 fdtv->demux.stop_feed = fdtv_stop_feed; 220 fdtv->demux.write_to_decoder = NULL; 221 222 err = dvb_dmx_init(&fdtv->demux); 223 if (err) 224 goto fail_unreg_adapter; 225 226 fdtv->dmxdev.filternum = 16; 227 fdtv->dmxdev.demux = &fdtv->demux.dmx; 228 fdtv->dmxdev.capabilities = 0; 229 230 err = dvb_dmxdev_init(&fdtv->dmxdev, &fdtv->adapter); 231 if (err) 232 goto fail_dmx_release; 233 234 fdtv->frontend.source = DMX_FRONTEND_0; 235 236 err = fdtv->demux.dmx.add_frontend(&fdtv->demux.dmx, 237 &fdtv->frontend); 238 if (err) 239 goto fail_dmxdev_release; 240 241 err = fdtv->demux.dmx.connect_frontend(&fdtv->demux.dmx, 242 &fdtv->frontend); 243 if (err) 244 goto fail_rem_frontend; 245 246 dvb_net_init(&fdtv->adapter, &fdtv->dvbnet, &fdtv->demux.dmx); 247 248 fdtv_frontend_init(fdtv); 249 err = dvb_register_frontend(&fdtv->adapter, &fdtv->fe); 250 if (err) 251 goto fail_net_release; 252 253 err = fdtv_ca_register(fdtv); 254 if (err) 255 dev_info(dev, "Conditional Access Module not enabled\n"); 256 257 return 0; 258 259fail_net_release: 260 dvb_net_release(&fdtv->dvbnet); 261 fdtv->demux.dmx.close(&fdtv->demux.dmx); 262fail_rem_frontend: 263 fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, 264 &fdtv->frontend); 265fail_dmxdev_release: 266 dvb_dmxdev_release(&fdtv->dmxdev); 267fail_dmx_release: 268 dvb_dmx_release(&fdtv->demux); 269fail_unreg_adapter: 270 dvb_unregister_adapter(&fdtv->adapter); 271fail_log: 272 dev_err(dev, "DVB initialization failed\n"); 273 return err; 274} 275 276 277