1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 Mantis PCI bridge driver 4 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 29 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); 30 31 int 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 } 57 EXPORT_SYMBOL_GPL(mantis_frontend_power); 58 59 void 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 } 75 EXPORT_SYMBOL_GPL(mantis_frontend_soft_reset); 76 77 static 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 91 static 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 tasklet_enable(&mantis->tasklet); 109 } 110 111 return mantis->feeds; 112 } 113 114 static 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 tasklet_disable(&mantis->tasklet); 129 mantis_dma_stop(mantis); 130 } 131 132 return 0; 133 } 134 135 int 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 tasklet_setup(&mantis->tasklet, mantis_dma_xfer); 209 tasklet_disable(&mantis->tasklet); 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 .. */ 237 err5: 238 tasklet_kill(&mantis->tasklet); 239 dvb_net_release(&mantis->dvbnet); 240 if (mantis->fe) { 241 dvb_unregister_frontend(mantis->fe); 242 dvb_frontend_detach(mantis->fe); 243 } 244 err4: 245 mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem); 246 247 err3: 248 mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw); 249 250 err2: 251 dvb_dmxdev_release(&mantis->dmxdev); 252 253 err1: 254 dvb_dmx_release(&mantis->demux); 255 256 err0: 257 dvb_unregister_adapter(&mantis->dvb_adapter); 258 259 return result; 260 } 261 EXPORT_SYMBOL_GPL(mantis_dvb_init); 262 263 int 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 tasklet_kill(&mantis->tasklet); 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 } 290 EXPORT_SYMBOL_GPL(mantis_dvb_exit); 291