1 /* 2 * Abilis Systems Single DVB-T Receiver 3 * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com> 4 * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2, or (at your option) 9 * any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 */ 16 #include <linux/kernel.h> 17 #include <linux/errno.h> 18 #include <linux/slab.h> 19 #include <linux/module.h> 20 #include <linux/mm.h> 21 #include <linux/kref.h> 22 #include <linux/uaccess.h> 23 #include <linux/usb.h> 24 25 /* header file for usb device driver*/ 26 #include "as102_drv.h" 27 #include "as102_fw.h" 28 #include "dvbdev.h" 29 30 int dual_tuner; 31 module_param_named(dual_tuner, dual_tuner, int, 0644); 32 MODULE_PARM_DESC(dual_tuner, "Activate Dual-Tuner config (default: off)"); 33 34 static int fw_upload = 1; 35 module_param_named(fw_upload, fw_upload, int, 0644); 36 MODULE_PARM_DESC(fw_upload, "Turn on/off default FW upload (default: on)"); 37 38 static int pid_filtering; 39 module_param_named(pid_filtering, pid_filtering, int, 0644); 40 MODULE_PARM_DESC(pid_filtering, "Activate HW PID filtering (default: off)"); 41 42 static int ts_auto_disable; 43 module_param_named(ts_auto_disable, ts_auto_disable, int, 0644); 44 MODULE_PARM_DESC(ts_auto_disable, "Stream Auto Enable on FW (default: off)"); 45 46 int elna_enable = 1; 47 module_param_named(elna_enable, elna_enable, int, 0644); 48 MODULE_PARM_DESC(elna_enable, "Activate eLNA (default: on)"); 49 50 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); 51 52 static void as102_stop_stream(struct as102_dev_t *dev) 53 { 54 struct as10x_bus_adapter_t *bus_adap; 55 56 if (dev != NULL) 57 bus_adap = &dev->bus_adap; 58 else 59 return; 60 61 if (bus_adap->ops->stop_stream != NULL) 62 bus_adap->ops->stop_stream(dev); 63 64 if (ts_auto_disable) { 65 if (mutex_lock_interruptible(&dev->bus_adap.lock)) 66 return; 67 68 if (as10x_cmd_stop_streaming(bus_adap) < 0) 69 dev_dbg(&dev->bus_adap.usb_dev->dev, 70 "as10x_cmd_stop_streaming failed\n"); 71 72 mutex_unlock(&dev->bus_adap.lock); 73 } 74 } 75 76 static int as102_start_stream(struct as102_dev_t *dev) 77 { 78 struct as10x_bus_adapter_t *bus_adap; 79 int ret = -EFAULT; 80 81 if (dev != NULL) 82 bus_adap = &dev->bus_adap; 83 else 84 return ret; 85 86 if (bus_adap->ops->start_stream != NULL) 87 ret = bus_adap->ops->start_stream(dev); 88 89 if (ts_auto_disable) { 90 if (mutex_lock_interruptible(&dev->bus_adap.lock)) 91 return -EFAULT; 92 93 ret = as10x_cmd_start_streaming(bus_adap); 94 95 mutex_unlock(&dev->bus_adap.lock); 96 } 97 98 return ret; 99 } 100 101 static int as10x_pid_filter(struct as102_dev_t *dev, 102 int index, u16 pid, int onoff) { 103 104 struct as10x_bus_adapter_t *bus_adap = &dev->bus_adap; 105 int ret = -EFAULT; 106 107 if (mutex_lock_interruptible(&dev->bus_adap.lock)) { 108 dev_dbg(&dev->bus_adap.usb_dev->dev, 109 "amutex_lock_interruptible(lock) failed !\n"); 110 return -EBUSY; 111 } 112 113 switch (onoff) { 114 case 0: 115 ret = as10x_cmd_del_PID_filter(bus_adap, (uint16_t) pid); 116 dev_dbg(&dev->bus_adap.usb_dev->dev, 117 "DEL_PID_FILTER([%02d] 0x%04x) ret = %d\n", 118 index, pid, ret); 119 break; 120 case 1: 121 { 122 struct as10x_ts_filter filter; 123 124 filter.type = TS_PID_TYPE_TS; 125 filter.idx = 0xFF; 126 filter.pid = pid; 127 128 ret = as10x_cmd_add_PID_filter(bus_adap, &filter); 129 dev_dbg(&dev->bus_adap.usb_dev->dev, 130 "ADD_PID_FILTER([%02d -> %02d], 0x%04x) ret = %d\n", 131 index, filter.idx, filter.pid, ret); 132 break; 133 } 134 } 135 136 mutex_unlock(&dev->bus_adap.lock); 137 return ret; 138 } 139 140 static int as102_dvb_dmx_start_feed(struct dvb_demux_feed *dvbdmxfeed) 141 { 142 int ret = 0; 143 struct dvb_demux *demux = dvbdmxfeed->demux; 144 struct as102_dev_t *as102_dev = demux->priv; 145 146 if (mutex_lock_interruptible(&as102_dev->sem)) 147 return -ERESTARTSYS; 148 149 if (pid_filtering) 150 as10x_pid_filter(as102_dev, dvbdmxfeed->index, 151 dvbdmxfeed->pid, 1); 152 153 if (as102_dev->streaming++ == 0) 154 ret = as102_start_stream(as102_dev); 155 156 mutex_unlock(&as102_dev->sem); 157 return ret; 158 } 159 160 static int as102_dvb_dmx_stop_feed(struct dvb_demux_feed *dvbdmxfeed) 161 { 162 struct dvb_demux *demux = dvbdmxfeed->demux; 163 struct as102_dev_t *as102_dev = demux->priv; 164 165 if (mutex_lock_interruptible(&as102_dev->sem)) 166 return -ERESTARTSYS; 167 168 if (--as102_dev->streaming == 0) 169 as102_stop_stream(as102_dev); 170 171 if (pid_filtering) 172 as10x_pid_filter(as102_dev, dvbdmxfeed->index, 173 dvbdmxfeed->pid, 0); 174 175 mutex_unlock(&as102_dev->sem); 176 return 0; 177 } 178 179 int as102_dvb_register(struct as102_dev_t *as102_dev) 180 { 181 struct device *dev = &as102_dev->bus_adap.usb_dev->dev; 182 int ret; 183 184 ret = dvb_register_adapter(&as102_dev->dvb_adap, 185 as102_dev->name, THIS_MODULE, 186 dev, adapter_nr); 187 if (ret < 0) { 188 dev_err(dev, "%s: dvb_register_adapter() failed: %d\n", 189 __func__, ret); 190 return ret; 191 } 192 193 as102_dev->dvb_dmx.priv = as102_dev; 194 as102_dev->dvb_dmx.filternum = pid_filtering ? 16 : 256; 195 as102_dev->dvb_dmx.feednum = 256; 196 as102_dev->dvb_dmx.start_feed = as102_dvb_dmx_start_feed; 197 as102_dev->dvb_dmx.stop_feed = as102_dvb_dmx_stop_feed; 198 199 as102_dev->dvb_dmx.dmx.capabilities = DMX_TS_FILTERING | 200 DMX_SECTION_FILTERING; 201 202 as102_dev->dvb_dmxdev.filternum = as102_dev->dvb_dmx.filternum; 203 as102_dev->dvb_dmxdev.demux = &as102_dev->dvb_dmx.dmx; 204 as102_dev->dvb_dmxdev.capabilities = 0; 205 206 ret = dvb_dmx_init(&as102_dev->dvb_dmx); 207 if (ret < 0) { 208 dev_err(dev, "%s: dvb_dmx_init() failed: %d\n", __func__, ret); 209 goto edmxinit; 210 } 211 212 ret = dvb_dmxdev_init(&as102_dev->dvb_dmxdev, &as102_dev->dvb_adap); 213 if (ret < 0) { 214 dev_err(dev, "%s: dvb_dmxdev_init() failed: %d\n", 215 __func__, ret); 216 goto edmxdinit; 217 } 218 219 /* Attach the frontend */ 220 as102_dev->dvb_fe = dvb_attach(as102_attach, as102_dev->name, 221 &as102_dev->bus_adap, 222 as102_dev->elna_cfg); 223 if (!as102_dev->dvb_fe) { 224 dev_err(dev, "%s: as102_attach() failed: %d", 225 __func__, ret); 226 goto efereg; 227 } 228 229 ret = dvb_register_frontend(&as102_dev->dvb_adap, as102_dev->dvb_fe); 230 if (ret < 0) { 231 dev_err(dev, "%s: as102_dvb_register_frontend() failed: %d", 232 __func__, ret); 233 goto efereg; 234 } 235 236 /* init bus mutex for token locking */ 237 mutex_init(&as102_dev->bus_adap.lock); 238 239 /* init start / stop stream mutex */ 240 mutex_init(&as102_dev->sem); 241 242 /* 243 * try to load as102 firmware. If firmware upload failed, we'll be 244 * able to upload it later. 245 */ 246 if (fw_upload) 247 try_then_request_module(as102_fw_upload(&as102_dev->bus_adap), 248 "firmware_class"); 249 250 pr_info("Registered device %s", as102_dev->name); 251 return 0; 252 253 efereg: 254 dvb_dmxdev_release(&as102_dev->dvb_dmxdev); 255 edmxdinit: 256 dvb_dmx_release(&as102_dev->dvb_dmx); 257 edmxinit: 258 dvb_unregister_adapter(&as102_dev->dvb_adap); 259 return ret; 260 } 261 262 void as102_dvb_unregister(struct as102_dev_t *as102_dev) 263 { 264 /* unregister as102 frontend */ 265 dvb_unregister_frontend(as102_dev->dvb_fe); 266 267 /* detach frontend */ 268 dvb_frontend_detach(as102_dev->dvb_fe); 269 270 /* unregister demux device */ 271 dvb_dmxdev_release(&as102_dev->dvb_dmxdev); 272 dvb_dmx_release(&as102_dev->dvb_dmx); 273 274 /* unregister dvb adapter */ 275 dvb_unregister_adapter(&as102_dev->dvb_adap); 276 277 pr_info("Unregistered device %s", as102_dev->name); 278 } 279 280 module_usb_driver(as102_usb_driver); 281 282 /* modinfo details */ 283 MODULE_DESCRIPTION(DRIVER_FULL_NAME); 284 MODULE_LICENSE("GPL"); 285 MODULE_AUTHOR("Pierrick Hascoet <pierrick.hascoet@abilis.com>"); 286