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 int err; 49 void *outp; 50 51 dprintk("dvb thread started\n"); 52 set_freezable(); 53 videobuf_read_start(&dvb->dvbq); 54 55 for (;;) { 56 /* fetch next buffer */ 57 buf = list_entry(dvb->dvbq.stream.next, 58 struct videobuf_buffer, stream); 59 list_del(&buf->stream); 60 err = videobuf_waiton(buf,0,1); 61 62 /* no more feeds left or stop_feed() asked us to quit */ 63 if (0 == dvb->nfeeds) 64 break; 65 if (kthread_should_stop()) 66 break; 67 try_to_freeze(); 68 69 /* feed buffer data to demux */ 70 outp = videobuf_queue_to_vaddr(&dvb->dvbq, buf); 71 72 if (buf->state == VIDEOBUF_DONE) 73 dvb_dmx_swfilter(&dvb->demux, outp, 74 buf->size); 75 76 /* requeue buffer */ 77 list_add_tail(&buf->stream,&dvb->dvbq.stream); 78 spin_lock_irqsave(dvb->dvbq.irqlock,flags); 79 dvb->dvbq.ops->buf_queue(&dvb->dvbq,buf); 80 spin_unlock_irqrestore(dvb->dvbq.irqlock,flags); 81 } 82 83 videobuf_read_stop(&dvb->dvbq); 84 dprintk("dvb thread stopped\n"); 85 86 /* Hmm, linux becomes *very* unhappy without this ... */ 87 while (!kthread_should_stop()) { 88 set_current_state(TASK_INTERRUPTIBLE); 89 schedule(); 90 } 91 return 0; 92} 93 94static int videobuf_dvb_start_feed(struct dvb_demux_feed *feed) 95{ 96 struct dvb_demux *demux = feed->demux; 97 struct videobuf_dvb *dvb = demux->priv; 98 int rc; 99 100 if (!demux->dmx.frontend) 101 return -EINVAL; 102 103 mutex_lock(&dvb->lock); 104 dvb->nfeeds++; 105 rc = dvb->nfeeds; 106 107 if (NULL != dvb->thread) 108 goto out; 109 dvb->thread = kthread_run(videobuf_dvb_thread, 110 dvb, "%s dvb", dvb->name); 111 if (IS_ERR(dvb->thread)) { 112 rc = PTR_ERR(dvb->thread); 113 dvb->thread = NULL; 114 } 115 116out: 117 mutex_unlock(&dvb->lock); 118 return rc; 119} 120 121static int videobuf_dvb_stop_feed(struct dvb_demux_feed *feed) 122{ 123 struct dvb_demux *demux = feed->demux; 124 struct videobuf_dvb *dvb = demux->priv; 125 int err = 0; 126 127 mutex_lock(&dvb->lock); 128 dvb->nfeeds--; 129 if (0 == dvb->nfeeds && NULL != dvb->thread) { 130 err = kthread_stop(dvb->thread); 131 dvb->thread = NULL; 132 } 133 mutex_unlock(&dvb->lock); 134 return err; 135} 136 137static int videobuf_dvb_register_adapter(struct videobuf_dvb_frontends *fe, 138 struct module *module, 139 void *adapter_priv, 140 struct device *device, 141 char *adapter_name, 142 short *adapter_nr, 143 int mfe_shared, 144 int (*fe_ioctl_override)(struct dvb_frontend *, 145 unsigned int, void *, unsigned int)) 146{ 147 int result; 148 149 mutex_init(&fe->lock); 150 151 /* register adapter */ 152 result = dvb_register_adapter(&fe->adapter, adapter_name, module, 153 device, adapter_nr); 154 if (result < 0) { 155 printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n", 156 adapter_name, result); 157 } 158 fe->adapter.priv = adapter_priv; 159 fe->adapter.mfe_shared = mfe_shared; 160 fe->adapter.fe_ioctl_override = fe_ioctl_override; 161 162 return result; 163} 164 165static int videobuf_dvb_register_frontend(struct dvb_adapter *adapter, 166 struct videobuf_dvb *dvb) 167{ 168 int result; 169 170 /* register frontend */ 171 result = dvb_register_frontend(adapter, dvb->frontend); 172 if (result < 0) { 173 printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n", 174 dvb->name, result); 175 goto fail_frontend; 176 } 177 178 /* register demux stuff */ 179 dvb->demux.dmx.capabilities = 180 DMX_TS_FILTERING | DMX_SECTION_FILTERING | 181 DMX_MEMORY_BASED_FILTERING; 182 dvb->demux.priv = dvb; 183 dvb->demux.filternum = 256; 184 dvb->demux.feednum = 256; 185 dvb->demux.start_feed = videobuf_dvb_start_feed; 186 dvb->demux.stop_feed = videobuf_dvb_stop_feed; 187 result = dvb_dmx_init(&dvb->demux); 188 if (result < 0) { 189 printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n", 190 dvb->name, result); 191 goto fail_dmx; 192 } 193 194 dvb->dmxdev.filternum = 256; 195 dvb->dmxdev.demux = &dvb->demux.dmx; 196 dvb->dmxdev.capabilities = 0; 197 result = dvb_dmxdev_init(&dvb->dmxdev, adapter); 198 199 if (result < 0) { 200 printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n", 201 dvb->name, result); 202 goto fail_dmxdev; 203 } 204 205 dvb->fe_hw.source = DMX_FRONTEND_0; 206 result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw); 207 if (result < 0) { 208 printk(KERN_WARNING "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n", 209 dvb->name, result); 210 goto fail_fe_hw; 211 } 212 213 dvb->fe_mem.source = DMX_MEMORY_FE; 214 result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem); 215 if (result < 0) { 216 printk(KERN_WARNING "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n", 217 dvb->name, result); 218 goto fail_fe_mem; 219 } 220 221 result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw); 222 if (result < 0) { 223 printk(KERN_WARNING "%s: connect_frontend failed (errno = %d)\n", 224 dvb->name, result); 225 goto fail_fe_conn; 226 } 227 228 /* register network adapter */ 229 dvb_net_init(adapter, &dvb->net, &dvb->demux.dmx); 230 if (dvb->net.dvbdev == NULL) { 231 result = -ENOMEM; 232 goto fail_fe_conn; 233 } 234 return 0; 235 236fail_fe_conn: 237 dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); 238fail_fe_mem: 239 dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); 240fail_fe_hw: 241 dvb_dmxdev_release(&dvb->dmxdev); 242fail_dmxdev: 243 dvb_dmx_release(&dvb->demux); 244fail_dmx: 245 dvb_unregister_frontend(dvb->frontend); 246fail_frontend: 247 dvb_frontend_detach(dvb->frontend); 248 dvb->frontend = NULL; 249 250 return result; 251} 252 253/* ------------------------------------------------------------------ */ 254/* Register a single adapter and one or more frontends */ 255int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f, 256 struct module *module, 257 void *adapter_priv, 258 struct device *device, 259 short *adapter_nr, 260 int mfe_shared, 261 int (*fe_ioctl_override)(struct dvb_frontend *, 262 unsigned int, void *, unsigned int)) 263{ 264 struct list_head *list, *q; 265 struct videobuf_dvb_frontend *fe; 266 int res; 267 268 fe = videobuf_dvb_get_frontend(f, 1); 269 if (!fe) { 270 printk(KERN_WARNING "Unable to register the adapter which has no frontends\n"); 271 return -EINVAL; 272 } 273 274 /* Bring up the adapter */ 275 res = videobuf_dvb_register_adapter(f, module, adapter_priv, device, 276 fe->dvb.name, adapter_nr, mfe_shared, fe_ioctl_override); 277 if (res < 0) { 278 printk(KERN_WARNING "videobuf_dvb_register_adapter failed (errno = %d)\n", res); 279 return res; 280 } 281 282 /* Attach all of the frontends to the adapter */ 283 mutex_lock(&f->lock); 284 list_for_each_safe(list, q, &f->felist) { 285 fe = list_entry(list, struct videobuf_dvb_frontend, felist); 286 res = videobuf_dvb_register_frontend(&f->adapter, &fe->dvb); 287 if (res < 0) { 288 printk(KERN_WARNING "%s: videobuf_dvb_register_frontend failed (errno = %d)\n", 289 fe->dvb.name, res); 290 goto err; 291 } 292 } 293 mutex_unlock(&f->lock); 294 return 0; 295 296err: 297 mutex_unlock(&f->lock); 298 videobuf_dvb_unregister_bus(f); 299 return res; 300} 301EXPORT_SYMBOL(videobuf_dvb_register_bus); 302 303void videobuf_dvb_unregister_bus(struct videobuf_dvb_frontends *f) 304{ 305 videobuf_dvb_dealloc_frontends(f); 306 307 dvb_unregister_adapter(&f->adapter); 308} 309EXPORT_SYMBOL(videobuf_dvb_unregister_bus); 310 311struct videobuf_dvb_frontend *videobuf_dvb_get_frontend( 312 struct videobuf_dvb_frontends *f, int id) 313{ 314 struct list_head *list, *q; 315 struct videobuf_dvb_frontend *fe, *ret = NULL; 316 317 mutex_lock(&f->lock); 318 319 list_for_each_safe(list, q, &f->felist) { 320 fe = list_entry(list, struct videobuf_dvb_frontend, felist); 321 if (fe->id == id) { 322 ret = fe; 323 break; 324 } 325 } 326 327 mutex_unlock(&f->lock); 328 329 return ret; 330} 331EXPORT_SYMBOL(videobuf_dvb_get_frontend); 332 333int videobuf_dvb_find_frontend(struct videobuf_dvb_frontends *f, 334 struct dvb_frontend *p) 335{ 336 struct list_head *list, *q; 337 struct videobuf_dvb_frontend *fe = NULL; 338 int ret = 0; 339 340 mutex_lock(&f->lock); 341 342 list_for_each_safe(list, q, &f->felist) { 343 fe = list_entry(list, struct videobuf_dvb_frontend, felist); 344 if (fe->dvb.frontend == p) { 345 ret = fe->id; 346 break; 347 } 348 } 349 350 mutex_unlock(&f->lock); 351 352 return ret; 353} 354EXPORT_SYMBOL(videobuf_dvb_find_frontend); 355 356struct videobuf_dvb_frontend *videobuf_dvb_alloc_frontend( 357 struct videobuf_dvb_frontends *f, int id) 358{ 359 struct videobuf_dvb_frontend *fe; 360 361 fe = kzalloc(sizeof(struct videobuf_dvb_frontend), GFP_KERNEL); 362 if (fe == NULL) 363 goto fail_alloc; 364 365 fe->id = id; 366 mutex_init(&fe->dvb.lock); 367 368 mutex_lock(&f->lock); 369 list_add_tail(&fe->felist, &f->felist); 370 mutex_unlock(&f->lock); 371 372fail_alloc: 373 return fe; 374} 375EXPORT_SYMBOL(videobuf_dvb_alloc_frontend); 376 377void videobuf_dvb_dealloc_frontends(struct videobuf_dvb_frontends *f) 378{ 379 struct list_head *list, *q; 380 struct videobuf_dvb_frontend *fe; 381 382 mutex_lock(&f->lock); 383 list_for_each_safe(list, q, &f->felist) { 384 fe = list_entry(list, struct videobuf_dvb_frontend, felist); 385 if (fe->dvb.net.dvbdev) { 386 dvb_net_release(&fe->dvb.net); 387 fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx, 388 &fe->dvb.fe_mem); 389 fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx, 390 &fe->dvb.fe_hw); 391 dvb_dmxdev_release(&fe->dvb.dmxdev); 392 dvb_dmx_release(&fe->dvb.demux); 393 dvb_unregister_frontend(fe->dvb.frontend); 394 } 395 if (fe->dvb.frontend) 396 /* always allocated, may have been reset */ 397 dvb_frontend_detach(fe->dvb.frontend); 398 list_del(list); /* remove list entry */ 399 kfree(fe); /* free frontend allocation */ 400 } 401 mutex_unlock(&f->lock); 402} 403EXPORT_SYMBOL(videobuf_dvb_dealloc_frontends); 404