1/* 2 * 3 * some helper function for simple DVB cards which simply DMA the 4 * complete transport stream and let the computer sort everything else 5 * (i.e. we are using the software demux, ...). Also uses the 6 * video-buf to manage DMA buffers. 7 * 8 * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SUSE Labs] 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 */ 15 16#include <linux/module.h> 17#include <linux/init.h> 18#include <linux/device.h> 19#include <linux/fs.h> 20#include <linux/kthread.h> 21#include <linux/file.h> 22#include <linux/slab.h> 23 24#include <linux/freezer.h> 25 26#include <media/videobuf-core.h> 27#include <media/videobuf-dvb.h> 28 29/* ------------------------------------------------------------------ */ 30 31MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); 32MODULE_LICENSE("GPL"); 33 34static unsigned int debug; 35module_param(debug, int, 0644); 36MODULE_PARM_DESC(debug,"enable debug messages"); 37 38#define dprintk(fmt, arg...) if (debug) \ 39 printk(KERN_DEBUG "%s/dvb: " fmt, dvb->name , ## arg) 40 41/* ------------------------------------------------------------------ */ 42 43static int videobuf_dvb_thread(void *data) 44{ 45 struct videobuf_dvb *dvb = data; 46 struct videobuf_buffer *buf; 47 unsigned long flags; 48 void *outp; 49 50 dprintk("dvb thread started\n"); 51 set_freezable(); 52 videobuf_read_start(&dvb->dvbq); 53 54 for (;;) { 55 /* fetch next buffer */ 56 buf = list_entry(dvb->dvbq.stream.next, 57 struct videobuf_buffer, stream); 58 list_del(&buf->stream); 59 videobuf_waiton(&dvb->dvbq, buf, 0, 1); 60 61 /* no more feeds left or stop_feed() asked us to quit */ 62 if (0 == dvb->nfeeds) 63 break; 64 if (kthread_should_stop()) 65 break; 66 try_to_freeze(); 67 68 /* feed buffer data to demux */ 69 outp = videobuf_queue_to_vaddr(&dvb->dvbq, buf); 70 71 if (buf->state == VIDEOBUF_DONE) 72 dvb_dmx_swfilter(&dvb->demux, outp, 73 buf->size); 74 75 /* requeue buffer */ 76 list_add_tail(&buf->stream,&dvb->dvbq.stream); 77 spin_lock_irqsave(dvb->dvbq.irqlock,flags); 78 dvb->dvbq.ops->buf_queue(&dvb->dvbq,buf); 79 spin_unlock_irqrestore(dvb->dvbq.irqlock,flags); 80 } 81 82 videobuf_read_stop(&dvb->dvbq); 83 dprintk("dvb thread stopped\n"); 84 85 /* Hmm, linux becomes *very* unhappy without this ... */ 86 while (!kthread_should_stop()) { 87 set_current_state(TASK_INTERRUPTIBLE); 88 schedule(); 89 } 90 return 0; 91} 92 93static int videobuf_dvb_start_feed(struct dvb_demux_feed *feed) 94{ 95 struct dvb_demux *demux = feed->demux; 96 struct videobuf_dvb *dvb = demux->priv; 97 int rc; 98 99 if (!demux->dmx.frontend) 100 return -EINVAL; 101 102 mutex_lock(&dvb->lock); 103 dvb->nfeeds++; 104 rc = dvb->nfeeds; 105 106 if (NULL != dvb->thread) 107 goto out; 108 dvb->thread = kthread_run(videobuf_dvb_thread, 109 dvb, "%s dvb", dvb->name); 110 if (IS_ERR(dvb->thread)) { 111 rc = PTR_ERR(dvb->thread); 112 dvb->thread = NULL; 113 } 114 115out: 116 mutex_unlock(&dvb->lock); 117 return rc; 118} 119 120static int videobuf_dvb_stop_feed(struct dvb_demux_feed *feed) 121{ 122 struct dvb_demux *demux = feed->demux; 123 struct videobuf_dvb *dvb = demux->priv; 124 int err = 0; 125 126 mutex_lock(&dvb->lock); 127 dvb->nfeeds--; 128 if (0 == dvb->nfeeds && NULL != dvb->thread) { 129 err = kthread_stop(dvb->thread); 130 dvb->thread = NULL; 131 } 132 mutex_unlock(&dvb->lock); 133 return err; 134} 135 136static int videobuf_dvb_register_adapter(struct videobuf_dvb_frontends *fe, 137 struct module *module, 138 void *adapter_priv, 139 struct device *device, 140 char *adapter_name, 141 short *adapter_nr, 142 int mfe_shared) 143{ 144 int result; 145 146 mutex_init(&fe->lock); 147 148 /* register adapter */ 149 result = dvb_register_adapter(&fe->adapter, adapter_name, module, 150 device, adapter_nr); 151 if (result < 0) { 152 printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n", 153 adapter_name, result); 154 } 155 fe->adapter.priv = adapter_priv; 156 fe->adapter.mfe_shared = mfe_shared; 157 158 return result; 159} 160 161static int videobuf_dvb_register_frontend(struct dvb_adapter *adapter, 162 struct videobuf_dvb *dvb) 163{ 164 int result; 165 166 /* register frontend */ 167 result = dvb_register_frontend(adapter, dvb->frontend); 168 if (result < 0) { 169 printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n", 170 dvb->name, result); 171 goto fail_frontend; 172 } 173 174 /* register demux stuff */ 175 dvb->demux.dmx.capabilities = 176 DMX_TS_FILTERING | DMX_SECTION_FILTERING | 177 DMX_MEMORY_BASED_FILTERING; 178 dvb->demux.priv = dvb; 179 dvb->demux.filternum = 256; 180 dvb->demux.feednum = 256; 181 dvb->demux.start_feed = videobuf_dvb_start_feed; 182 dvb->demux.stop_feed = videobuf_dvb_stop_feed; 183 result = dvb_dmx_init(&dvb->demux); 184 if (result < 0) { 185 printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n", 186 dvb->name, result); 187 goto fail_dmx; 188 } 189 190 dvb->dmxdev.filternum = 256; 191 dvb->dmxdev.demux = &dvb->demux.dmx; 192 dvb->dmxdev.capabilities = 0; 193 result = dvb_dmxdev_init(&dvb->dmxdev, adapter); 194 195 if (result < 0) { 196 printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n", 197 dvb->name, result); 198 goto fail_dmxdev; 199 } 200 201 dvb->fe_hw.source = DMX_FRONTEND_0; 202 result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw); 203 if (result < 0) { 204 printk(KERN_WARNING "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n", 205 dvb->name, result); 206 goto fail_fe_hw; 207 } 208 209 dvb->fe_mem.source = DMX_MEMORY_FE; 210 result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem); 211 if (result < 0) { 212 printk(KERN_WARNING "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n", 213 dvb->name, result); 214 goto fail_fe_mem; 215 } 216 217 result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw); 218 if (result < 0) { 219 printk(KERN_WARNING "%s: connect_frontend failed (errno = %d)\n", 220 dvb->name, result); 221 goto fail_fe_conn; 222 } 223 224 /* register network adapter */ 225 result = dvb_net_init(adapter, &dvb->net, &dvb->demux.dmx); 226 if (result < 0) { 227 printk(KERN_WARNING "%s: dvb_net_init failed (errno = %d)\n", 228 dvb->name, result); 229 goto fail_fe_conn; 230 } 231 return 0; 232 233fail_fe_conn: 234 dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); 235fail_fe_mem: 236 dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); 237fail_fe_hw: 238 dvb_dmxdev_release(&dvb->dmxdev); 239fail_dmxdev: 240 dvb_dmx_release(&dvb->demux); 241fail_dmx: 242 dvb_unregister_frontend(dvb->frontend); 243fail_frontend: 244 dvb_frontend_detach(dvb->frontend); 245 dvb->frontend = NULL; 246 247 return result; 248} 249 250/* ------------------------------------------------------------------ */ 251/* Register a single adapter and one or more frontends */ 252int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f, 253 struct module *module, 254 void *adapter_priv, 255 struct device *device, 256 short *adapter_nr, 257 int mfe_shared) 258{ 259 struct list_head *list, *q; 260 struct videobuf_dvb_frontend *fe; 261 int res; 262 263 fe = videobuf_dvb_get_frontend(f, 1); 264 if (!fe) { 265 printk(KERN_WARNING "Unable to register the adapter which has no frontends\n"); 266 return -EINVAL; 267 } 268 269 /* Bring up the adapter */ 270 res = videobuf_dvb_register_adapter(f, module, adapter_priv, device, 271 fe->dvb.name, adapter_nr, mfe_shared); 272 if (res < 0) { 273 printk(KERN_WARNING "videobuf_dvb_register_adapter failed (errno = %d)\n", res); 274 return res; 275 } 276 277 /* Attach all of the frontends to the adapter */ 278 mutex_lock(&f->lock); 279 list_for_each_safe(list, q, &f->felist) { 280 fe = list_entry(list, struct videobuf_dvb_frontend, felist); 281 res = videobuf_dvb_register_frontend(&f->adapter, &fe->dvb); 282 if (res < 0) { 283 printk(KERN_WARNING "%s: videobuf_dvb_register_frontend failed (errno = %d)\n", 284 fe->dvb.name, res); 285 goto err; 286 } 287 } 288 mutex_unlock(&f->lock); 289 return 0; 290 291err: 292 mutex_unlock(&f->lock); 293 videobuf_dvb_unregister_bus(f); 294 return res; 295} 296EXPORT_SYMBOL(videobuf_dvb_register_bus); 297 298void videobuf_dvb_unregister_bus(struct videobuf_dvb_frontends *f) 299{ 300 videobuf_dvb_dealloc_frontends(f); 301 302 dvb_unregister_adapter(&f->adapter); 303} 304EXPORT_SYMBOL(videobuf_dvb_unregister_bus); 305 306struct videobuf_dvb_frontend *videobuf_dvb_get_frontend( 307 struct videobuf_dvb_frontends *f, int id) 308{ 309 struct list_head *list, *q; 310 struct videobuf_dvb_frontend *fe, *ret = NULL; 311 312 mutex_lock(&f->lock); 313 314 list_for_each_safe(list, q, &f->felist) { 315 fe = list_entry(list, struct videobuf_dvb_frontend, felist); 316 if (fe->id == id) { 317 ret = fe; 318 break; 319 } 320 } 321 322 mutex_unlock(&f->lock); 323 324 return ret; 325} 326EXPORT_SYMBOL(videobuf_dvb_get_frontend); 327 328int videobuf_dvb_find_frontend(struct videobuf_dvb_frontends *f, 329 struct dvb_frontend *p) 330{ 331 struct list_head *list, *q; 332 struct videobuf_dvb_frontend *fe = NULL; 333 int ret = 0; 334 335 mutex_lock(&f->lock); 336 337 list_for_each_safe(list, q, &f->felist) { 338 fe = list_entry(list, struct videobuf_dvb_frontend, felist); 339 if (fe->dvb.frontend == p) { 340 ret = fe->id; 341 break; 342 } 343 } 344 345 mutex_unlock(&f->lock); 346 347 return ret; 348} 349EXPORT_SYMBOL(videobuf_dvb_find_frontend); 350 351struct videobuf_dvb_frontend *videobuf_dvb_alloc_frontend( 352 struct videobuf_dvb_frontends *f, int id) 353{ 354 struct videobuf_dvb_frontend *fe; 355 356 fe = kzalloc(sizeof(struct videobuf_dvb_frontend), GFP_KERNEL); 357 if (fe == NULL) 358 goto fail_alloc; 359 360 fe->id = id; 361 mutex_init(&fe->dvb.lock); 362 363 mutex_lock(&f->lock); 364 list_add_tail(&fe->felist, &f->felist); 365 mutex_unlock(&f->lock); 366 367fail_alloc: 368 return fe; 369} 370EXPORT_SYMBOL(videobuf_dvb_alloc_frontend); 371 372void videobuf_dvb_dealloc_frontends(struct videobuf_dvb_frontends *f) 373{ 374 struct list_head *list, *q; 375 struct videobuf_dvb_frontend *fe; 376 377 mutex_lock(&f->lock); 378 list_for_each_safe(list, q, &f->felist) { 379 fe = list_entry(list, struct videobuf_dvb_frontend, felist); 380 if (fe->dvb.net.dvbdev) { 381 dvb_net_release(&fe->dvb.net); 382 fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx, 383 &fe->dvb.fe_mem); 384 fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx, 385 &fe->dvb.fe_hw); 386 dvb_dmxdev_release(&fe->dvb.dmxdev); 387 dvb_dmx_release(&fe->dvb.demux); 388 dvb_unregister_frontend(fe->dvb.frontend); 389 } 390 if (fe->dvb.frontend) 391 /* always allocated, may have been reset */ 392 dvb_frontend_detach(fe->dvb.frontend); 393 list_del(list); /* remove list entry */ 394 kfree(fe); /* free frontend allocation */ 395 } 396 mutex_unlock(&f->lock); 397} 398EXPORT_SYMBOL(videobuf_dvb_dealloc_frontends); 399