125aee3deSMauro Carvalho Chehab /* 225aee3deSMauro Carvalho Chehab Mantis PCI bridge driver 325aee3deSMauro Carvalho Chehab Copyright (C) Manu Abraham (abraham.manu@gmail.com) 425aee3deSMauro Carvalho Chehab 525aee3deSMauro Carvalho Chehab This program is free software; you can redistribute it and/or modify 625aee3deSMauro Carvalho Chehab it under the terms of the GNU General Public License as published by 725aee3deSMauro Carvalho Chehab the Free Software Foundation; either version 2 of the License, or 825aee3deSMauro Carvalho Chehab (at your option) any later version. 925aee3deSMauro Carvalho Chehab 1025aee3deSMauro Carvalho Chehab This program is distributed in the hope that it will be useful, 1125aee3deSMauro Carvalho Chehab but WITHOUT ANY WARRANTY; without even the implied warranty of 1225aee3deSMauro Carvalho Chehab MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1325aee3deSMauro Carvalho Chehab GNU General Public License for more details. 1425aee3deSMauro Carvalho Chehab 1525aee3deSMauro Carvalho Chehab You should have received a copy of the GNU General Public License 1625aee3deSMauro Carvalho Chehab along with this program; if not, write to the Free Software 1725aee3deSMauro Carvalho Chehab Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 1825aee3deSMauro Carvalho Chehab */ 1925aee3deSMauro Carvalho Chehab 2025aee3deSMauro Carvalho Chehab #include <linux/kernel.h> 2125aee3deSMauro Carvalho Chehab #include <linux/bitops.h> 2225aee3deSMauro Carvalho Chehab 2325aee3deSMauro Carvalho Chehab #include <linux/signal.h> 2425aee3deSMauro Carvalho Chehab #include <linux/sched.h> 2525aee3deSMauro Carvalho Chehab #include <linux/interrupt.h> 2625aee3deSMauro Carvalho Chehab #include <linux/pci.h> 2725aee3deSMauro Carvalho Chehab #include <linux/i2c.h> 2825aee3deSMauro Carvalho Chehab 2925aee3deSMauro Carvalho Chehab #include "dmxdev.h" 3025aee3deSMauro Carvalho Chehab #include "dvbdev.h" 3125aee3deSMauro Carvalho Chehab #include "dvb_demux.h" 3225aee3deSMauro Carvalho Chehab #include "dvb_frontend.h" 3325aee3deSMauro Carvalho Chehab #include "dvb_net.h" 3425aee3deSMauro Carvalho Chehab 3525aee3deSMauro Carvalho Chehab #include "mantis_common.h" 3625aee3deSMauro Carvalho Chehab #include "mantis_dma.h" 3725aee3deSMauro Carvalho Chehab #include "mantis_ca.h" 3825aee3deSMauro Carvalho Chehab #include "mantis_ioc.h" 3925aee3deSMauro Carvalho Chehab #include "mantis_dvb.h" 4025aee3deSMauro Carvalho Chehab 4125aee3deSMauro Carvalho Chehab DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); 4225aee3deSMauro Carvalho Chehab 4325aee3deSMauro Carvalho Chehab int mantis_frontend_power(struct mantis_pci *mantis, enum mantis_power power) 4425aee3deSMauro Carvalho Chehab { 4525aee3deSMauro Carvalho Chehab struct mantis_hwconfig *config = mantis->hwconfig; 4625aee3deSMauro Carvalho Chehab 4725aee3deSMauro Carvalho Chehab switch (power) { 4825aee3deSMauro Carvalho Chehab case POWER_ON: 4925aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 1, "Power ON"); 5025aee3deSMauro Carvalho Chehab mantis_gpio_set_bits(mantis, config->power, POWER_ON); 5125aee3deSMauro Carvalho Chehab msleep(100); 5225aee3deSMauro Carvalho Chehab mantis_gpio_set_bits(mantis, config->power, POWER_ON); 5325aee3deSMauro Carvalho Chehab msleep(100); 5425aee3deSMauro Carvalho Chehab break; 5525aee3deSMauro Carvalho Chehab 5625aee3deSMauro Carvalho Chehab case POWER_OFF: 5725aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 1, "Power OFF"); 5825aee3deSMauro Carvalho Chehab mantis_gpio_set_bits(mantis, config->power, POWER_OFF); 5925aee3deSMauro Carvalho Chehab msleep(100); 6025aee3deSMauro Carvalho Chehab break; 6125aee3deSMauro Carvalho Chehab 6225aee3deSMauro Carvalho Chehab default: 6325aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 1, "Unknown state <%02x>", power); 6425aee3deSMauro Carvalho Chehab return -1; 6525aee3deSMauro Carvalho Chehab } 6625aee3deSMauro Carvalho Chehab 6725aee3deSMauro Carvalho Chehab return 0; 6825aee3deSMauro Carvalho Chehab } 6925aee3deSMauro Carvalho Chehab EXPORT_SYMBOL_GPL(mantis_frontend_power); 7025aee3deSMauro Carvalho Chehab 7125aee3deSMauro Carvalho Chehab void mantis_frontend_soft_reset(struct mantis_pci *mantis) 7225aee3deSMauro Carvalho Chehab { 7325aee3deSMauro Carvalho Chehab struct mantis_hwconfig *config = mantis->hwconfig; 7425aee3deSMauro Carvalho Chehab 7525aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 1, "Frontend RESET"); 7625aee3deSMauro Carvalho Chehab mantis_gpio_set_bits(mantis, config->reset, 0); 7725aee3deSMauro Carvalho Chehab msleep(100); 7825aee3deSMauro Carvalho Chehab mantis_gpio_set_bits(mantis, config->reset, 0); 7925aee3deSMauro Carvalho Chehab msleep(100); 8025aee3deSMauro Carvalho Chehab mantis_gpio_set_bits(mantis, config->reset, 1); 8125aee3deSMauro Carvalho Chehab msleep(100); 8225aee3deSMauro Carvalho Chehab mantis_gpio_set_bits(mantis, config->reset, 1); 8325aee3deSMauro Carvalho Chehab msleep(100); 8425aee3deSMauro Carvalho Chehab 8525aee3deSMauro Carvalho Chehab return; 8625aee3deSMauro Carvalho Chehab } 8725aee3deSMauro Carvalho Chehab EXPORT_SYMBOL_GPL(mantis_frontend_soft_reset); 8825aee3deSMauro Carvalho Chehab 8925aee3deSMauro Carvalho Chehab static int mantis_frontend_shutdown(struct mantis_pci *mantis) 9025aee3deSMauro Carvalho Chehab { 9125aee3deSMauro Carvalho Chehab int err; 9225aee3deSMauro Carvalho Chehab 9325aee3deSMauro Carvalho Chehab mantis_frontend_soft_reset(mantis); 9425aee3deSMauro Carvalho Chehab err = mantis_frontend_power(mantis, POWER_OFF); 9525aee3deSMauro Carvalho Chehab if (err != 0) { 9625aee3deSMauro Carvalho Chehab dprintk(MANTIS_ERROR, 1, "Frontend POWER OFF failed! <%d>", err); 9725aee3deSMauro Carvalho Chehab return 1; 9825aee3deSMauro Carvalho Chehab } 9925aee3deSMauro Carvalho Chehab 10025aee3deSMauro Carvalho Chehab return 0; 10125aee3deSMauro Carvalho Chehab } 10225aee3deSMauro Carvalho Chehab 10325aee3deSMauro Carvalho Chehab static int mantis_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed) 10425aee3deSMauro Carvalho Chehab { 10525aee3deSMauro Carvalho Chehab struct dvb_demux *dvbdmx = dvbdmxfeed->demux; 10625aee3deSMauro Carvalho Chehab struct mantis_pci *mantis = dvbdmx->priv; 10725aee3deSMauro Carvalho Chehab 10825aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 1, "Mantis DVB Start feed"); 10925aee3deSMauro Carvalho Chehab if (!dvbdmx->dmx.frontend) { 11025aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 1, "no frontend ?"); 11125aee3deSMauro Carvalho Chehab return -EINVAL; 11225aee3deSMauro Carvalho Chehab } 11325aee3deSMauro Carvalho Chehab 11425aee3deSMauro Carvalho Chehab mantis->feeds++; 11525aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 1, "mantis start feed, feeds=%d", mantis->feeds); 11625aee3deSMauro Carvalho Chehab 11725aee3deSMauro Carvalho Chehab if (mantis->feeds == 1) { 11825aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 1, "mantis start feed & dma"); 11925aee3deSMauro Carvalho Chehab mantis_dma_start(mantis); 12025aee3deSMauro Carvalho Chehab tasklet_enable(&mantis->tasklet); 12125aee3deSMauro Carvalho Chehab } 12225aee3deSMauro Carvalho Chehab 12325aee3deSMauro Carvalho Chehab return mantis->feeds; 12425aee3deSMauro Carvalho Chehab } 12525aee3deSMauro Carvalho Chehab 12625aee3deSMauro Carvalho Chehab static int mantis_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) 12725aee3deSMauro Carvalho Chehab { 12825aee3deSMauro Carvalho Chehab struct dvb_demux *dvbdmx = dvbdmxfeed->demux; 12925aee3deSMauro Carvalho Chehab struct mantis_pci *mantis = dvbdmx->priv; 13025aee3deSMauro Carvalho Chehab 13125aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 1, "Mantis DVB Stop feed"); 13225aee3deSMauro Carvalho Chehab if (!dvbdmx->dmx.frontend) { 13325aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 1, "no frontend ?"); 13425aee3deSMauro Carvalho Chehab return -EINVAL; 13525aee3deSMauro Carvalho Chehab } 13625aee3deSMauro Carvalho Chehab 13725aee3deSMauro Carvalho Chehab mantis->feeds--; 13825aee3deSMauro Carvalho Chehab if (mantis->feeds == 0) { 13925aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 1, "mantis stop feed and dma"); 14025aee3deSMauro Carvalho Chehab tasklet_disable(&mantis->tasklet); 14125aee3deSMauro Carvalho Chehab mantis_dma_stop(mantis); 14225aee3deSMauro Carvalho Chehab } 14325aee3deSMauro Carvalho Chehab 14425aee3deSMauro Carvalho Chehab return 0; 14525aee3deSMauro Carvalho Chehab } 14625aee3deSMauro Carvalho Chehab 1474c62e976SGreg Kroah-Hartman int mantis_dvb_init(struct mantis_pci *mantis) 14825aee3deSMauro Carvalho Chehab { 14925aee3deSMauro Carvalho Chehab struct mantis_hwconfig *config = mantis->hwconfig; 15025aee3deSMauro Carvalho Chehab int result = -1; 15125aee3deSMauro Carvalho Chehab 15225aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 1, "dvb_register_adapter"); 15325aee3deSMauro Carvalho Chehab 15425aee3deSMauro Carvalho Chehab result = dvb_register_adapter(&mantis->dvb_adapter, 15525aee3deSMauro Carvalho Chehab "Mantis DVB adapter", 15625aee3deSMauro Carvalho Chehab THIS_MODULE, 15725aee3deSMauro Carvalho Chehab &mantis->pdev->dev, 15825aee3deSMauro Carvalho Chehab adapter_nr); 15925aee3deSMauro Carvalho Chehab 16025aee3deSMauro Carvalho Chehab if (result < 0) { 16125aee3deSMauro Carvalho Chehab 16225aee3deSMauro Carvalho Chehab dprintk(MANTIS_ERROR, 1, "Error registering adapter"); 16325aee3deSMauro Carvalho Chehab return -ENODEV; 16425aee3deSMauro Carvalho Chehab } 16525aee3deSMauro Carvalho Chehab 16625aee3deSMauro Carvalho Chehab mantis->dvb_adapter.priv = mantis; 16725aee3deSMauro Carvalho Chehab mantis->demux.dmx.capabilities = DMX_TS_FILTERING | 16825aee3deSMauro Carvalho Chehab DMX_SECTION_FILTERING | 16925aee3deSMauro Carvalho Chehab DMX_MEMORY_BASED_FILTERING; 17025aee3deSMauro Carvalho Chehab 17125aee3deSMauro Carvalho Chehab mantis->demux.priv = mantis; 17225aee3deSMauro Carvalho Chehab mantis->demux.filternum = 256; 17325aee3deSMauro Carvalho Chehab mantis->demux.feednum = 256; 17425aee3deSMauro Carvalho Chehab mantis->demux.start_feed = mantis_dvb_start_feed; 17525aee3deSMauro Carvalho Chehab mantis->demux.stop_feed = mantis_dvb_stop_feed; 17625aee3deSMauro Carvalho Chehab mantis->demux.write_to_decoder = NULL; 17725aee3deSMauro Carvalho Chehab 17825aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 1, "dvb_dmx_init"); 17925aee3deSMauro Carvalho Chehab result = dvb_dmx_init(&mantis->demux); 18025aee3deSMauro Carvalho Chehab if (result < 0) { 18125aee3deSMauro Carvalho Chehab dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); 18225aee3deSMauro Carvalho Chehab 18325aee3deSMauro Carvalho Chehab goto err0; 18425aee3deSMauro Carvalho Chehab } 18525aee3deSMauro Carvalho Chehab 18625aee3deSMauro Carvalho Chehab mantis->dmxdev.filternum = 256; 18725aee3deSMauro Carvalho Chehab mantis->dmxdev.demux = &mantis->demux.dmx; 18825aee3deSMauro Carvalho Chehab mantis->dmxdev.capabilities = 0; 18925aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 1, "dvb_dmxdev_init"); 19025aee3deSMauro Carvalho Chehab 19125aee3deSMauro Carvalho Chehab result = dvb_dmxdev_init(&mantis->dmxdev, &mantis->dvb_adapter); 19225aee3deSMauro Carvalho Chehab if (result < 0) { 19325aee3deSMauro Carvalho Chehab 19425aee3deSMauro Carvalho Chehab dprintk(MANTIS_ERROR, 1, "dvb_dmxdev_init failed, ERROR=%d", result); 19525aee3deSMauro Carvalho Chehab goto err1; 19625aee3deSMauro Carvalho Chehab } 19725aee3deSMauro Carvalho Chehab 19825aee3deSMauro Carvalho Chehab mantis->fe_hw.source = DMX_FRONTEND_0; 19925aee3deSMauro Carvalho Chehab result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_hw); 20025aee3deSMauro Carvalho Chehab if (result < 0) { 20125aee3deSMauro Carvalho Chehab 20225aee3deSMauro Carvalho Chehab dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); 20325aee3deSMauro Carvalho Chehab goto err2; 20425aee3deSMauro Carvalho Chehab } 20525aee3deSMauro Carvalho Chehab 20625aee3deSMauro Carvalho Chehab mantis->fe_mem.source = DMX_MEMORY_FE; 20725aee3deSMauro Carvalho Chehab result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_mem); 20825aee3deSMauro Carvalho Chehab if (result < 0) { 20925aee3deSMauro Carvalho Chehab dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); 21025aee3deSMauro Carvalho Chehab goto err3; 21125aee3deSMauro Carvalho Chehab } 21225aee3deSMauro Carvalho Chehab 21325aee3deSMauro Carvalho Chehab result = mantis->demux.dmx.connect_frontend(&mantis->demux.dmx, &mantis->fe_hw); 21425aee3deSMauro Carvalho Chehab if (result < 0) { 21525aee3deSMauro Carvalho Chehab dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); 21625aee3deSMauro Carvalho Chehab goto err4; 21725aee3deSMauro Carvalho Chehab } 21825aee3deSMauro Carvalho Chehab 21925aee3deSMauro Carvalho Chehab dvb_net_init(&mantis->dvb_adapter, &mantis->dvbnet, &mantis->demux.dmx); 22025aee3deSMauro Carvalho Chehab tasklet_init(&mantis->tasklet, mantis_dma_xfer, (unsigned long) mantis); 22125aee3deSMauro Carvalho Chehab tasklet_disable(&mantis->tasklet); 22225aee3deSMauro Carvalho Chehab if (mantis->hwconfig) { 22325aee3deSMauro Carvalho Chehab result = config->frontend_init(mantis, mantis->fe); 22425aee3deSMauro Carvalho Chehab if (result < 0) { 22525aee3deSMauro Carvalho Chehab dprintk(MANTIS_ERROR, 1, "!!! NO Frontends found !!!"); 22625aee3deSMauro Carvalho Chehab goto err5; 22725aee3deSMauro Carvalho Chehab } else { 22825aee3deSMauro Carvalho Chehab if (mantis->fe == NULL) { 22925aee3deSMauro Carvalho Chehab dprintk(MANTIS_ERROR, 1, "FE <NULL>"); 23025aee3deSMauro Carvalho Chehab goto err5; 23125aee3deSMauro Carvalho Chehab } 23225aee3deSMauro Carvalho Chehab 23325aee3deSMauro Carvalho Chehab if (dvb_register_frontend(&mantis->dvb_adapter, mantis->fe)) { 23425aee3deSMauro Carvalho Chehab dprintk(MANTIS_ERROR, 1, "ERROR: Frontend registration failed"); 23525aee3deSMauro Carvalho Chehab 23625aee3deSMauro Carvalho Chehab if (mantis->fe->ops.release) 23725aee3deSMauro Carvalho Chehab mantis->fe->ops.release(mantis->fe); 23825aee3deSMauro Carvalho Chehab 23925aee3deSMauro Carvalho Chehab mantis->fe = NULL; 24025aee3deSMauro Carvalho Chehab goto err5; 24125aee3deSMauro Carvalho Chehab } 24225aee3deSMauro Carvalho Chehab } 24325aee3deSMauro Carvalho Chehab } 24425aee3deSMauro Carvalho Chehab 24525aee3deSMauro Carvalho Chehab return 0; 24625aee3deSMauro Carvalho Chehab 24725aee3deSMauro Carvalho Chehab /* Error conditions .. */ 24825aee3deSMauro Carvalho Chehab err5: 24925aee3deSMauro Carvalho Chehab tasklet_kill(&mantis->tasklet); 25025aee3deSMauro Carvalho Chehab dvb_net_release(&mantis->dvbnet); 25125aee3deSMauro Carvalho Chehab if (mantis->fe) { 25225aee3deSMauro Carvalho Chehab dvb_unregister_frontend(mantis->fe); 25325aee3deSMauro Carvalho Chehab dvb_frontend_detach(mantis->fe); 25425aee3deSMauro Carvalho Chehab } 25525aee3deSMauro Carvalho Chehab err4: 25625aee3deSMauro Carvalho Chehab mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem); 25725aee3deSMauro Carvalho Chehab 25825aee3deSMauro Carvalho Chehab err3: 25925aee3deSMauro Carvalho Chehab mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw); 26025aee3deSMauro Carvalho Chehab 26125aee3deSMauro Carvalho Chehab err2: 26225aee3deSMauro Carvalho Chehab dvb_dmxdev_release(&mantis->dmxdev); 26325aee3deSMauro Carvalho Chehab 26425aee3deSMauro Carvalho Chehab err1: 26525aee3deSMauro Carvalho Chehab dvb_dmx_release(&mantis->demux); 26625aee3deSMauro Carvalho Chehab 26725aee3deSMauro Carvalho Chehab err0: 26825aee3deSMauro Carvalho Chehab dvb_unregister_adapter(&mantis->dvb_adapter); 26925aee3deSMauro Carvalho Chehab 27025aee3deSMauro Carvalho Chehab return result; 27125aee3deSMauro Carvalho Chehab } 27225aee3deSMauro Carvalho Chehab EXPORT_SYMBOL_GPL(mantis_dvb_init); 27325aee3deSMauro Carvalho Chehab 2744c62e976SGreg Kroah-Hartman int mantis_dvb_exit(struct mantis_pci *mantis) 27525aee3deSMauro Carvalho Chehab { 27625aee3deSMauro Carvalho Chehab int err; 27725aee3deSMauro Carvalho Chehab 27825aee3deSMauro Carvalho Chehab if (mantis->fe) { 27925aee3deSMauro Carvalho Chehab /* mantis_ca_exit(mantis); */ 28025aee3deSMauro Carvalho Chehab err = mantis_frontend_shutdown(mantis); 28125aee3deSMauro Carvalho Chehab if (err != 0) 28225aee3deSMauro Carvalho Chehab dprintk(MANTIS_ERROR, 1, "Frontend exit while POWER ON! <%d>", err); 28325aee3deSMauro Carvalho Chehab dvb_unregister_frontend(mantis->fe); 28425aee3deSMauro Carvalho Chehab dvb_frontend_detach(mantis->fe); 28525aee3deSMauro Carvalho Chehab } 28625aee3deSMauro Carvalho Chehab 28725aee3deSMauro Carvalho Chehab tasklet_kill(&mantis->tasklet); 28825aee3deSMauro Carvalho Chehab dvb_net_release(&mantis->dvbnet); 28925aee3deSMauro Carvalho Chehab 29025aee3deSMauro Carvalho Chehab mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem); 29125aee3deSMauro Carvalho Chehab mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw); 29225aee3deSMauro Carvalho Chehab 29325aee3deSMauro Carvalho Chehab dvb_dmxdev_release(&mantis->dmxdev); 29425aee3deSMauro Carvalho Chehab dvb_dmx_release(&mantis->demux); 29525aee3deSMauro Carvalho Chehab 29625aee3deSMauro Carvalho Chehab dprintk(MANTIS_DEBUG, 1, "dvb_unregister_adapter"); 29725aee3deSMauro Carvalho Chehab dvb_unregister_adapter(&mantis->dvb_adapter); 29825aee3deSMauro Carvalho Chehab 29925aee3deSMauro Carvalho Chehab return 0; 30025aee3deSMauro Carvalho Chehab } 30125aee3deSMauro Carvalho Chehab EXPORT_SYMBOL_GPL(mantis_dvb_exit); 302