| |
| |
| |
| |
| |
| |
| |
| |
| |
| #include <linux/completion.h> |
| #include <linux/delay.h> |
| #include <linux/device.h> |
| #include <linux/dvb/dmx.h> |
| #include <linux/errno.h> |
| #include <linux/init.h> |
| #include <linux/interrupt.h> |
| #include <linux/io.h> |
| #include <linux/ioport.h> |
| #include <linux/module.h> |
| #include <linux/slab.h> |
| #include <linux/time.h> |
| #include <linux/wait.h> |
| |
| #include <media/dmxdev.h> |
| #include <media/dvbdev.h> |
| #include <media/dvb_demux.h> |
| #include <media/dvb_frontend.h> |
| #include <media/dvb_net.h> |
| |
| #include "c8sectpfe-common.h" |
| #include "c8sectpfe-core.h" |
| #include "c8sectpfe-dvb.h" |
| |
| static int register_dvb(struct stdemux *demux, struct dvb_adapter *adap, |
| <------><------><------><------>void *start_feed, void *stop_feed, |
| <------><------><------><------>struct c8sectpfei *fei) |
| { |
| <------>int result; |
| |
| <------>demux->dvb_demux.dmx.capabilities = DMX_TS_FILTERING | |
| <------><------><------><------><------>DMX_SECTION_FILTERING | |
| <------><------><------><------><------>DMX_MEMORY_BASED_FILTERING; |
| |
| <------>demux->dvb_demux.priv = demux; |
| <------>demux->dvb_demux.filternum = C8SECTPFE_MAXCHANNEL; |
| <------>demux->dvb_demux.feednum = C8SECTPFE_MAXCHANNEL; |
| |
| <------>demux->dvb_demux.start_feed = start_feed; |
| <------>demux->dvb_demux.stop_feed = stop_feed; |
| <------>demux->dvb_demux.write_to_decoder = NULL; |
| |
| <------>result = dvb_dmx_init(&demux->dvb_demux); |
| <------>if (result < 0) { |
| <------><------>dev_err(fei->dev, "dvb_dmx_init failed (errno = %d)\n", |
| <------><------><------>result); |
| <------><------>goto err_dmx; |
| <------>} |
| |
| <------>demux->dmxdev.filternum = demux->dvb_demux.filternum; |
| <------>demux->dmxdev.demux = &demux->dvb_demux.dmx; |
| <------>demux->dmxdev.capabilities = 0; |
| |
| <------>result = dvb_dmxdev_init(&demux->dmxdev, adap); |
| <------>if (result < 0) { |
| <------><------>dev_err(fei->dev, "dvb_dmxdev_init failed (errno = %d)\n", |
| <------><------><------>result); |
| |
| <------><------>goto err_dmxdev; |
| <------>} |
| |
| <------>demux->hw_frontend.source = DMX_FRONTEND_0 + demux->tsin_index; |
| |
| <------>result = demux->dvb_demux.dmx.add_frontend(&demux->dvb_demux.dmx, |
| <------><------><------><------><------><------>&demux->hw_frontend); |
| <------>if (result < 0) { |
| <------><------>dev_err(fei->dev, "add_frontend failed (errno = %d)\n", result); |
| <------><------>goto err_fe_hw; |
| <------>} |
| |
| <------>demux->mem_frontend.source = DMX_MEMORY_FE; |
| <------>result = demux->dvb_demux.dmx.add_frontend(&demux->dvb_demux.dmx, |
| <------><------><------><------><------><------>&demux->mem_frontend); |
| <------>if (result < 0) { |
| <------><------>dev_err(fei->dev, "add_frontend failed (%d)\n", result); |
| <------><------>goto err_fe_mem; |
| <------>} |
| |
| <------>result = demux->dvb_demux.dmx.connect_frontend(&demux->dvb_demux.dmx, |
| <------><------><------><------><------><------><------>&demux->hw_frontend); |
| <------>if (result < 0) { |
| <------><------>dev_err(fei->dev, "connect_frontend (%d)\n", result); |
| <------><------>goto err_fe_con; |
| <------>} |
| |
| <------>return 0; |
| |
| err_fe_con: |
| <------>demux->dvb_demux.dmx.remove_frontend(&demux->dvb_demux.dmx, |
| <------><------><------><------><------><------> &demux->mem_frontend); |
| err_fe_mem: |
| <------>demux->dvb_demux.dmx.remove_frontend(&demux->dvb_demux.dmx, |
| <------><------><------><------><------><------> &demux->hw_frontend); |
| err_fe_hw: |
| <------>dvb_dmxdev_release(&demux->dmxdev); |
| err_dmxdev: |
| <------>dvb_dmx_release(&demux->dvb_demux); |
| err_dmx: |
| <------>return result; |
| |
| } |
| |
| static void unregister_dvb(struct stdemux *demux) |
| { |
| |
| <------>demux->dvb_demux.dmx.remove_frontend(&demux->dvb_demux.dmx, |
| <------><------><------><------><------><------> &demux->mem_frontend); |
| |
| <------>demux->dvb_demux.dmx.remove_frontend(&demux->dvb_demux.dmx, |
| <------><------><------><------><------><------> &demux->hw_frontend); |
| |
| <------>dvb_dmxdev_release(&demux->dmxdev); |
| |
| <------>dvb_dmx_release(&demux->dvb_demux); |
| } |
| |
| static struct c8sectpfe *c8sectpfe_create(struct c8sectpfei *fei, |
| <------><------><------><------>void *start_feed, |
| <------><------><------><------>void *stop_feed) |
| { |
| <------>struct c8sectpfe *c8sectpfe; |
| <------>int result; |
| <------>int i, j; |
| |
| <------>short int ids[] = { -1 }; |
| |
| <------>c8sectpfe = kzalloc(sizeof(struct c8sectpfe), GFP_KERNEL); |
| <------>if (!c8sectpfe) |
| <------><------>goto err1; |
| |
| <------>mutex_init(&c8sectpfe->lock); |
| |
| <------>c8sectpfe->device = fei->dev; |
| |
| <------>result = dvb_register_adapter(&c8sectpfe->adapter, "STi c8sectpfe", |
| <------><------><------><------><------>THIS_MODULE, fei->dev, ids); |
| <------>if (result < 0) { |
| <------><------>dev_err(fei->dev, "dvb_register_adapter failed (errno = %d)\n", |
| <------><------><------>result); |
| <------><------>goto err2; |
| <------>} |
| |
| <------>c8sectpfe->adapter.priv = fei; |
| |
| <------>for (i = 0; i < fei->tsin_count; i++) { |
| |
| <------><------>c8sectpfe->demux[i].tsin_index = i; |
| <------><------>c8sectpfe->demux[i].c8sectpfei = fei; |
| |
| <------><------>result = register_dvb(&c8sectpfe->demux[i], &c8sectpfe->adapter, |
| <------><------><------><------>start_feed, stop_feed, fei); |
| <------><------>if (result < 0) { |
| <------><------><------>dev_err(fei->dev, |
| <------><------><------><------>"register_dvb feed=%d failed (errno = %d)\n", |
| <------><------><------><------>result, i); |
| |
| <------><------><------> |
| <------><------><------>for (j = 0; j < i; j++) |
| <------><------><------><------>unregister_dvb(&c8sectpfe->demux[j]); |
| <------><------><------>goto err3; |
| <------><------>} |
| <------>} |
| |
| <------>c8sectpfe->num_feeds = fei->tsin_count; |
| |
| <------>return c8sectpfe; |
| err3: |
| <------>dvb_unregister_adapter(&c8sectpfe->adapter); |
| err2: |
| <------>kfree(c8sectpfe); |
| err1: |
| <------>return NULL; |
| }; |
| |
| static void c8sectpfe_delete(struct c8sectpfe *c8sectpfe) |
| { |
| <------>int i; |
| |
| <------>if (!c8sectpfe) |
| <------><------>return; |
| |
| <------>for (i = 0; i < c8sectpfe->num_feeds; i++) |
| <------><------>unregister_dvb(&c8sectpfe->demux[i]); |
| |
| <------>dvb_unregister_adapter(&c8sectpfe->adapter); |
| |
| <------>kfree(c8sectpfe); |
| }; |
| |
| void c8sectpfe_tuner_unregister_frontend(struct c8sectpfe *c8sectpfe, |
| <------><------><------><------><------>struct c8sectpfei *fei) |
| { |
| <------>int n; |
| <------>struct channel_info *tsin; |
| |
| <------>for (n = 0; n < fei->tsin_count; n++) { |
| |
| <------><------>tsin = fei->channel_data[n]; |
| |
| <------><------>if (tsin) { |
| <------><------><------>if (tsin->frontend) { |
| <------><------><------><------>dvb_unregister_frontend(tsin->frontend); |
| <------><------><------><------>dvb_frontend_detach(tsin->frontend); |
| <------><------><------>} |
| |
| <------><------><------>i2c_put_adapter(tsin->i2c_adapter); |
| |
| <------><------><------>if (tsin->i2c_client) { |
| <------><------><------><------>module_put(tsin->i2c_client->dev.driver->owner); |
| <------><------><------><------>i2c_unregister_device(tsin->i2c_client); |
| <------><------><------>} |
| <------><------>} |
| <------>} |
| |
| <------>c8sectpfe_delete(c8sectpfe); |
| }; |
| |
| int c8sectpfe_tuner_register_frontend(struct c8sectpfe **c8sectpfe, |
| <------><------><------><------>struct c8sectpfei *fei, |
| <------><------><------><------>void *start_feed, |
| <------><------><------><------>void *stop_feed) |
| { |
| <------>struct channel_info *tsin; |
| <------>struct dvb_frontend *frontend; |
| <------>int n, res; |
| |
| <------>*c8sectpfe = c8sectpfe_create(fei, start_feed, stop_feed); |
| <------>if (!*c8sectpfe) |
| <------><------>return -ENOMEM; |
| |
| <------>for (n = 0; n < fei->tsin_count; n++) { |
| <------><------>tsin = fei->channel_data[n]; |
| |
| <------><------>res = c8sectpfe_frontend_attach(&frontend, *c8sectpfe, tsin, n); |
| <------><------>if (res) |
| <------><------><------>goto err; |
| |
| <------><------>res = dvb_register_frontend(&c8sectpfe[0]->adapter, frontend); |
| <------><------>if (res < 0) { |
| <------><------><------>dev_err(fei->dev, "dvb_register_frontend failed (%d)\n", |
| <------><------><------><------>res); |
| <------><------><------>goto err; |
| <------><------>} |
| |
| <------><------>tsin->frontend = frontend; |
| <------>} |
| |
| <------>return 0; |
| |
| err: |
| <------>c8sectpfe_tuner_unregister_frontend(*c8sectpfe, fei); |
| <------>return res; |
| } |
| |