291 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 Mantis PCI bridge driver4 Copyright (C) Manu Abraham (abraham.manu@gmail.com)5 6*/7 8#include <linux/kernel.h>9#include <linux/bitops.h>10 11#include <linux/signal.h>12#include <linux/sched.h>13#include <linux/interrupt.h>14#include <linux/pci.h>15#include <linux/i2c.h>16 17#include <media/dmxdev.h>18#include <media/dvbdev.h>19#include <media/dvb_demux.h>20#include <media/dvb_frontend.h>21#include <media/dvb_net.h>22 23#include "mantis_common.h"24#include "mantis_dma.h"25#include "mantis_ca.h"26#include "mantis_ioc.h"27#include "mantis_dvb.h"28 29DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);30 31int mantis_frontend_power(struct mantis_pci *mantis, enum mantis_power power)32{33 struct mantis_hwconfig *config = mantis->hwconfig;34 35 switch (power) {36 case POWER_ON:37 dprintk(MANTIS_DEBUG, 1, "Power ON");38 mantis_gpio_set_bits(mantis, config->power, POWER_ON);39 msleep(100);40 mantis_gpio_set_bits(mantis, config->power, POWER_ON);41 msleep(100);42 break;43 44 case POWER_OFF:45 dprintk(MANTIS_DEBUG, 1, "Power OFF");46 mantis_gpio_set_bits(mantis, config->power, POWER_OFF);47 msleep(100);48 break;49 50 default:51 dprintk(MANTIS_DEBUG, 1, "Unknown state <%02x>", power);52 return -1;53 }54 55 return 0;56}57EXPORT_SYMBOL_GPL(mantis_frontend_power);58 59void mantis_frontend_soft_reset(struct mantis_pci *mantis)60{61 struct mantis_hwconfig *config = mantis->hwconfig;62 63 dprintk(MANTIS_DEBUG, 1, "Frontend RESET");64 mantis_gpio_set_bits(mantis, config->reset, 0);65 msleep(100);66 mantis_gpio_set_bits(mantis, config->reset, 0);67 msleep(100);68 mantis_gpio_set_bits(mantis, config->reset, 1);69 msleep(100);70 mantis_gpio_set_bits(mantis, config->reset, 1);71 msleep(100);72 73 return;74}75EXPORT_SYMBOL_GPL(mantis_frontend_soft_reset);76 77static int mantis_frontend_shutdown(struct mantis_pci *mantis)78{79 int err;80 81 mantis_frontend_soft_reset(mantis);82 err = mantis_frontend_power(mantis, POWER_OFF);83 if (err != 0) {84 dprintk(MANTIS_ERROR, 1, "Frontend POWER OFF failed! <%d>", err);85 return 1;86 }87 88 return 0;89}90 91static int mantis_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)92{93 struct dvb_demux *dvbdmx = dvbdmxfeed->demux;94 struct mantis_pci *mantis = dvbdmx->priv;95 96 dprintk(MANTIS_DEBUG, 1, "Mantis DVB Start feed");97 if (!dvbdmx->dmx.frontend) {98 dprintk(MANTIS_DEBUG, 1, "no frontend ?");99 return -EINVAL;100 }101 102 mantis->feeds++;103 dprintk(MANTIS_DEBUG, 1, "mantis start feed, feeds=%d", mantis->feeds);104 105 if (mantis->feeds == 1) {106 dprintk(MANTIS_DEBUG, 1, "mantis start feed & dma");107 mantis_dma_start(mantis);108 enable_and_queue_work(system_bh_wq, &mantis->bh_work);109 }110 111 return mantis->feeds;112}113 114static int mantis_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)115{116 struct dvb_demux *dvbdmx = dvbdmxfeed->demux;117 struct mantis_pci *mantis = dvbdmx->priv;118 119 dprintk(MANTIS_DEBUG, 1, "Mantis DVB Stop feed");120 if (!dvbdmx->dmx.frontend) {121 dprintk(MANTIS_DEBUG, 1, "no frontend ?");122 return -EINVAL;123 }124 125 mantis->feeds--;126 if (mantis->feeds == 0) {127 dprintk(MANTIS_DEBUG, 1, "mantis stop feed and dma");128 disable_work_sync(&mantis->bh_work);129 mantis_dma_stop(mantis);130 }131 132 return 0;133}134 135int mantis_dvb_init(struct mantis_pci *mantis)136{137 struct mantis_hwconfig *config = mantis->hwconfig;138 int result;139 140 dprintk(MANTIS_DEBUG, 1, "dvb_register_adapter");141 142 result = dvb_register_adapter(&mantis->dvb_adapter,143 "Mantis DVB adapter",144 THIS_MODULE,145 &mantis->pdev->dev,146 adapter_nr);147 148 if (result < 0) {149 150 dprintk(MANTIS_ERROR, 1, "Error registering adapter");151 return -ENODEV;152 }153 154 mantis->dvb_adapter.priv = mantis;155 mantis->demux.dmx.capabilities = DMX_TS_FILTERING |156 DMX_SECTION_FILTERING |157 DMX_MEMORY_BASED_FILTERING;158 159 mantis->demux.priv = mantis;160 mantis->demux.filternum = 256;161 mantis->demux.feednum = 256;162 mantis->demux.start_feed = mantis_dvb_start_feed;163 mantis->demux.stop_feed = mantis_dvb_stop_feed;164 mantis->demux.write_to_decoder = NULL;165 166 dprintk(MANTIS_DEBUG, 1, "dvb_dmx_init");167 result = dvb_dmx_init(&mantis->demux);168 if (result < 0) {169 dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);170 171 goto err0;172 }173 174 mantis->dmxdev.filternum = 256;175 mantis->dmxdev.demux = &mantis->demux.dmx;176 mantis->dmxdev.capabilities = 0;177 dprintk(MANTIS_DEBUG, 1, "dvb_dmxdev_init");178 179 result = dvb_dmxdev_init(&mantis->dmxdev, &mantis->dvb_adapter);180 if (result < 0) {181 182 dprintk(MANTIS_ERROR, 1, "dvb_dmxdev_init failed, ERROR=%d", result);183 goto err1;184 }185 186 mantis->fe_hw.source = DMX_FRONTEND_0;187 result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_hw);188 if (result < 0) {189 190 dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);191 goto err2;192 }193 194 mantis->fe_mem.source = DMX_MEMORY_FE;195 result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_mem);196 if (result < 0) {197 dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);198 goto err3;199 }200 201 result = mantis->demux.dmx.connect_frontend(&mantis->demux.dmx, &mantis->fe_hw);202 if (result < 0) {203 dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);204 goto err4;205 }206 207 dvb_net_init(&mantis->dvb_adapter, &mantis->dvbnet, &mantis->demux.dmx);208 INIT_WORK(&mantis->bh_work, mantis_dma_xfer);209 disable_work_sync(&mantis->bh_work);210 if (mantis->hwconfig) {211 result = config->frontend_init(mantis, mantis->fe);212 if (result < 0) {213 dprintk(MANTIS_ERROR, 1, "!!! NO Frontends found !!!");214 goto err5;215 } else {216 if (mantis->fe == NULL) {217 result = -ENOMEM;218 dprintk(MANTIS_ERROR, 1, "FE <NULL>");219 goto err5;220 }221 result = dvb_register_frontend(&mantis->dvb_adapter, mantis->fe);222 if (result) {223 dprintk(MANTIS_ERROR, 1, "ERROR: Frontend registration failed");224 225 if (mantis->fe->ops.release)226 mantis->fe->ops.release(mantis->fe);227 228 mantis->fe = NULL;229 goto err5;230 }231 }232 }233 234 return 0;235 236 /* Error conditions .. */237err5:238 cancel_work_sync(&mantis->bh_work);239 dvb_net_release(&mantis->dvbnet);240 if (mantis->fe) {241 dvb_unregister_frontend(mantis->fe);242 dvb_frontend_detach(mantis->fe);243 }244err4:245 mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem);246 247err3:248 mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw);249 250err2:251 dvb_dmxdev_release(&mantis->dmxdev);252 253err1:254 dvb_dmx_release(&mantis->demux);255 256err0:257 dvb_unregister_adapter(&mantis->dvb_adapter);258 259 return result;260}261EXPORT_SYMBOL_GPL(mantis_dvb_init);262 263int mantis_dvb_exit(struct mantis_pci *mantis)264{265 int err;266 267 if (mantis->fe) {268 /* mantis_ca_exit(mantis); */269 err = mantis_frontend_shutdown(mantis);270 if (err != 0)271 dprintk(MANTIS_ERROR, 1, "Frontend exit while POWER ON! <%d>", err);272 dvb_unregister_frontend(mantis->fe);273 dvb_frontend_detach(mantis->fe);274 }275 276 cancel_work_sync(&mantis->bh_work);277 dvb_net_release(&mantis->dvbnet);278 279 mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem);280 mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw);281 282 dvb_dmxdev_release(&mantis->dmxdev);283 dvb_dmx_release(&mantis->demux);284 285 dprintk(MANTIS_DEBUG, 1, "dvb_unregister_adapter");286 dvb_unregister_adapter(&mantis->dvb_adapter);287 288 return 0;289}290EXPORT_SYMBOL_GPL(mantis_dvb_exit);291