root/drivers/media/usb/as102/as102_drv.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. as102_stop_stream
  2. as102_start_stream
  3. as10x_pid_filter
  4. as102_dvb_dmx_start_feed
  5. as102_dvb_dmx_stop_feed
  6. as102_set_tune
  7. as102_get_tps
  8. as102_get_status
  9. as102_get_stats
  10. as102_stream_ctrl
  11. as102_dvb_register
  12. as102_dvb_unregister

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Abilis Systems Single DVB-T Receiver
   4  * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
   5  * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
   6  */
   7 #include <linux/kernel.h>
   8 #include <linux/errno.h>
   9 #include <linux/slab.h>
  10 #include <linux/module.h>
  11 #include <linux/mm.h>
  12 #include <linux/kref.h>
  13 #include <linux/uaccess.h>
  14 #include <linux/usb.h>
  15 
  16 /* header file for usb device driver*/
  17 #include "as102_drv.h"
  18 #include "as10x_cmd.h"
  19 #include "as102_fe.h"
  20 #include "as102_fw.h"
  21 #include <media/dvbdev.h>
  22 
  23 int dual_tuner;
  24 module_param_named(dual_tuner, dual_tuner, int, 0644);
  25 MODULE_PARM_DESC(dual_tuner, "Activate Dual-Tuner config (default: off)");
  26 
  27 static int fw_upload = 1;
  28 module_param_named(fw_upload, fw_upload, int, 0644);
  29 MODULE_PARM_DESC(fw_upload, "Turn on/off default FW upload (default: on)");
  30 
  31 static int pid_filtering;
  32 module_param_named(pid_filtering, pid_filtering, int, 0644);
  33 MODULE_PARM_DESC(pid_filtering, "Activate HW PID filtering (default: off)");
  34 
  35 static int ts_auto_disable;
  36 module_param_named(ts_auto_disable, ts_auto_disable, int, 0644);
  37 MODULE_PARM_DESC(ts_auto_disable, "Stream Auto Enable on FW (default: off)");
  38 
  39 int elna_enable = 1;
  40 module_param_named(elna_enable, elna_enable, int, 0644);
  41 MODULE_PARM_DESC(elna_enable, "Activate eLNA (default: on)");
  42 
  43 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
  44 
  45 static void as102_stop_stream(struct as102_dev_t *dev)
  46 {
  47         struct as10x_bus_adapter_t *bus_adap;
  48 
  49         if (dev != NULL)
  50                 bus_adap = &dev->bus_adap;
  51         else
  52                 return;
  53 
  54         if (bus_adap->ops->stop_stream != NULL)
  55                 bus_adap->ops->stop_stream(dev);
  56 
  57         if (ts_auto_disable) {
  58                 if (mutex_lock_interruptible(&dev->bus_adap.lock))
  59                         return;
  60 
  61                 if (as10x_cmd_stop_streaming(bus_adap) < 0)
  62                         dev_dbg(&dev->bus_adap.usb_dev->dev,
  63                                 "as10x_cmd_stop_streaming failed\n");
  64 
  65                 mutex_unlock(&dev->bus_adap.lock);
  66         }
  67 }
  68 
  69 static int as102_start_stream(struct as102_dev_t *dev)
  70 {
  71         struct as10x_bus_adapter_t *bus_adap;
  72         int ret = -EFAULT;
  73 
  74         if (dev != NULL)
  75                 bus_adap = &dev->bus_adap;
  76         else
  77                 return ret;
  78 
  79         if (bus_adap->ops->start_stream != NULL)
  80                 ret = bus_adap->ops->start_stream(dev);
  81 
  82         if (ts_auto_disable) {
  83                 if (mutex_lock_interruptible(&dev->bus_adap.lock))
  84                         return -EFAULT;
  85 
  86                 ret = as10x_cmd_start_streaming(bus_adap);
  87 
  88                 mutex_unlock(&dev->bus_adap.lock);
  89         }
  90 
  91         return ret;
  92 }
  93 
  94 static int as10x_pid_filter(struct as102_dev_t *dev,
  95                             int index, u16 pid, int onoff) {
  96 
  97         struct as10x_bus_adapter_t *bus_adap = &dev->bus_adap;
  98         int ret = -EFAULT;
  99 
 100         if (mutex_lock_interruptible(&dev->bus_adap.lock)) {
 101                 dev_dbg(&dev->bus_adap.usb_dev->dev,
 102                         "amutex_lock_interruptible(lock) failed !\n");
 103                 return -EBUSY;
 104         }
 105 
 106         switch (onoff) {
 107         case 0:
 108                 ret = as10x_cmd_del_PID_filter(bus_adap, (uint16_t) pid);
 109                 dev_dbg(&dev->bus_adap.usb_dev->dev,
 110                         "DEL_PID_FILTER([%02d] 0x%04x) ret = %d\n",
 111                         index, pid, ret);
 112                 break;
 113         case 1:
 114         {
 115                 struct as10x_ts_filter filter;
 116 
 117                 filter.type = TS_PID_TYPE_TS;
 118                 filter.idx = 0xFF;
 119                 filter.pid = pid;
 120 
 121                 ret = as10x_cmd_add_PID_filter(bus_adap, &filter);
 122                 dev_dbg(&dev->bus_adap.usb_dev->dev,
 123                         "ADD_PID_FILTER([%02d -> %02d], 0x%04x) ret = %d\n",
 124                         index, filter.idx, filter.pid, ret);
 125                 break;
 126         }
 127         }
 128 
 129         mutex_unlock(&dev->bus_adap.lock);
 130         return ret;
 131 }
 132 
 133 static int as102_dvb_dmx_start_feed(struct dvb_demux_feed *dvbdmxfeed)
 134 {
 135         int ret = 0;
 136         struct dvb_demux *demux = dvbdmxfeed->demux;
 137         struct as102_dev_t *as102_dev = demux->priv;
 138 
 139         if (mutex_lock_interruptible(&as102_dev->sem))
 140                 return -ERESTARTSYS;
 141 
 142         if (pid_filtering)
 143                 as10x_pid_filter(as102_dev, dvbdmxfeed->index,
 144                                  dvbdmxfeed->pid, 1);
 145 
 146         if (as102_dev->streaming++ == 0)
 147                 ret = as102_start_stream(as102_dev);
 148 
 149         mutex_unlock(&as102_dev->sem);
 150         return ret;
 151 }
 152 
 153 static int as102_dvb_dmx_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
 154 {
 155         struct dvb_demux *demux = dvbdmxfeed->demux;
 156         struct as102_dev_t *as102_dev = demux->priv;
 157 
 158         if (mutex_lock_interruptible(&as102_dev->sem))
 159                 return -ERESTARTSYS;
 160 
 161         if (--as102_dev->streaming == 0)
 162                 as102_stop_stream(as102_dev);
 163 
 164         if (pid_filtering)
 165                 as10x_pid_filter(as102_dev, dvbdmxfeed->index,
 166                                  dvbdmxfeed->pid, 0);
 167 
 168         mutex_unlock(&as102_dev->sem);
 169         return 0;
 170 }
 171 
 172 static int as102_set_tune(void *priv, struct as10x_tune_args *tune_args)
 173 {
 174         struct as10x_bus_adapter_t *bus_adap = priv;
 175         int ret;
 176 
 177         /* Set frontend arguments */
 178         if (mutex_lock_interruptible(&bus_adap->lock))
 179                 return -EBUSY;
 180 
 181         ret =  as10x_cmd_set_tune(bus_adap, tune_args);
 182         if (ret != 0)
 183                 dev_dbg(&bus_adap->usb_dev->dev,
 184                         "as10x_cmd_set_tune failed. (err = %d)\n", ret);
 185 
 186         mutex_unlock(&bus_adap->lock);
 187 
 188         return ret;
 189 }
 190 
 191 static int as102_get_tps(void *priv, struct as10x_tps *tps)
 192 {
 193         struct as10x_bus_adapter_t *bus_adap = priv;
 194         int ret;
 195 
 196         if (mutex_lock_interruptible(&bus_adap->lock))
 197                 return -EBUSY;
 198 
 199         /* send abilis command: GET_TPS */
 200         ret = as10x_cmd_get_tps(bus_adap, tps);
 201 
 202         mutex_unlock(&bus_adap->lock);
 203 
 204         return ret;
 205 }
 206 
 207 static int as102_get_status(void *priv, struct as10x_tune_status *tstate)
 208 {
 209         struct as10x_bus_adapter_t *bus_adap = priv;
 210         int ret;
 211 
 212         if (mutex_lock_interruptible(&bus_adap->lock))
 213                 return -EBUSY;
 214 
 215         /* send abilis command: GET_TUNE_STATUS */
 216         ret = as10x_cmd_get_tune_status(bus_adap, tstate);
 217         if (ret < 0) {
 218                 dev_dbg(&bus_adap->usb_dev->dev,
 219                         "as10x_cmd_get_tune_status failed (err = %d)\n",
 220                         ret);
 221         }
 222 
 223         mutex_unlock(&bus_adap->lock);
 224 
 225         return ret;
 226 }
 227 
 228 static int as102_get_stats(void *priv, struct as10x_demod_stats *demod_stats)
 229 {
 230         struct as10x_bus_adapter_t *bus_adap = priv;
 231         int ret;
 232 
 233         if (mutex_lock_interruptible(&bus_adap->lock))
 234                 return -EBUSY;
 235 
 236         /* send abilis command: GET_TUNE_STATUS */
 237         ret = as10x_cmd_get_demod_stats(bus_adap, demod_stats);
 238         if (ret < 0) {
 239                 dev_dbg(&bus_adap->usb_dev->dev,
 240                         "as10x_cmd_get_demod_stats failed (probably not tuned)\n");
 241         } else {
 242                 dev_dbg(&bus_adap->usb_dev->dev,
 243                         "demod status: fc: 0x%08x, bad fc: 0x%08x, bytes corrected: 0x%08x , MER: 0x%04x\n",
 244                         demod_stats->frame_count,
 245                         demod_stats->bad_frame_count,
 246                         demod_stats->bytes_fixed_by_rs,
 247                         demod_stats->mer);
 248         }
 249         mutex_unlock(&bus_adap->lock);
 250 
 251         return ret;
 252 }
 253 
 254 static int as102_stream_ctrl(void *priv, int acquire, uint32_t elna_cfg)
 255 {
 256         struct as10x_bus_adapter_t *bus_adap = priv;
 257         int ret;
 258 
 259         if (mutex_lock_interruptible(&bus_adap->lock))
 260                 return -EBUSY;
 261 
 262         if (acquire) {
 263                 if (elna_enable)
 264                         as10x_cmd_set_context(bus_adap,
 265                                               CONTEXT_LNA, elna_cfg);
 266 
 267                 ret = as10x_cmd_turn_on(bus_adap);
 268         } else {
 269                 ret = as10x_cmd_turn_off(bus_adap);
 270         }
 271 
 272         mutex_unlock(&bus_adap->lock);
 273 
 274         return ret;
 275 }
 276 
 277 static const struct as102_fe_ops as102_fe_ops = {
 278         .set_tune = as102_set_tune,
 279         .get_tps  = as102_get_tps,
 280         .get_status = as102_get_status,
 281         .get_stats = as102_get_stats,
 282         .stream_ctrl = as102_stream_ctrl,
 283 };
 284 
 285 int as102_dvb_register(struct as102_dev_t *as102_dev)
 286 {
 287         struct device *dev = &as102_dev->bus_adap.usb_dev->dev;
 288         int ret;
 289 
 290         ret = dvb_register_adapter(&as102_dev->dvb_adap,
 291                            as102_dev->name, THIS_MODULE,
 292                            dev, adapter_nr);
 293         if (ret < 0) {
 294                 dev_err(dev, "%s: dvb_register_adapter() failed: %d\n",
 295                         __func__, ret);
 296                 return ret;
 297         }
 298 
 299         as102_dev->dvb_dmx.priv = as102_dev;
 300         as102_dev->dvb_dmx.filternum = pid_filtering ? 16 : 256;
 301         as102_dev->dvb_dmx.feednum = 256;
 302         as102_dev->dvb_dmx.start_feed = as102_dvb_dmx_start_feed;
 303         as102_dev->dvb_dmx.stop_feed = as102_dvb_dmx_stop_feed;
 304 
 305         as102_dev->dvb_dmx.dmx.capabilities = DMX_TS_FILTERING |
 306                                               DMX_SECTION_FILTERING;
 307 
 308         as102_dev->dvb_dmxdev.filternum = as102_dev->dvb_dmx.filternum;
 309         as102_dev->dvb_dmxdev.demux = &as102_dev->dvb_dmx.dmx;
 310         as102_dev->dvb_dmxdev.capabilities = 0;
 311 
 312         ret = dvb_dmx_init(&as102_dev->dvb_dmx);
 313         if (ret < 0) {
 314                 dev_err(dev, "%s: dvb_dmx_init() failed: %d\n", __func__, ret);
 315                 goto edmxinit;
 316         }
 317 
 318         ret = dvb_dmxdev_init(&as102_dev->dvb_dmxdev, &as102_dev->dvb_adap);
 319         if (ret < 0) {
 320                 dev_err(dev, "%s: dvb_dmxdev_init() failed: %d\n",
 321                         __func__, ret);
 322                 goto edmxdinit;
 323         }
 324 
 325         /* Attach the frontend */
 326         as102_dev->dvb_fe = dvb_attach(as102_attach, as102_dev->name,
 327                                        &as102_fe_ops,
 328                                        &as102_dev->bus_adap,
 329                                        as102_dev->elna_cfg);
 330         if (!as102_dev->dvb_fe) {
 331                 ret = -ENODEV;
 332                 dev_err(dev, "%s: as102_attach() failed: %d",
 333                     __func__, ret);
 334                 goto efereg;
 335         }
 336 
 337         ret =  dvb_register_frontend(&as102_dev->dvb_adap, as102_dev->dvb_fe);
 338         if (ret < 0) {
 339                 dev_err(dev, "%s: as102_dvb_register_frontend() failed: %d",
 340                     __func__, ret);
 341                 goto efereg;
 342         }
 343 
 344         /* init bus mutex for token locking */
 345         mutex_init(&as102_dev->bus_adap.lock);
 346 
 347         /* init start / stop stream mutex */
 348         mutex_init(&as102_dev->sem);
 349 
 350         /*
 351          * try to load as102 firmware. If firmware upload failed, we'll be
 352          * able to upload it later.
 353          */
 354         if (fw_upload)
 355                 try_then_request_module(as102_fw_upload(&as102_dev->bus_adap),
 356                                 "firmware_class");
 357 
 358         pr_info("Registered device %s", as102_dev->name);
 359         return 0;
 360 
 361 efereg:
 362         dvb_dmxdev_release(&as102_dev->dvb_dmxdev);
 363 edmxdinit:
 364         dvb_dmx_release(&as102_dev->dvb_dmx);
 365 edmxinit:
 366         dvb_unregister_adapter(&as102_dev->dvb_adap);
 367         return ret;
 368 }
 369 
 370 void as102_dvb_unregister(struct as102_dev_t *as102_dev)
 371 {
 372         /* unregister as102 frontend */
 373         dvb_unregister_frontend(as102_dev->dvb_fe);
 374 
 375         /* detach frontend */
 376         dvb_frontend_detach(as102_dev->dvb_fe);
 377 
 378         /* unregister demux device */
 379         dvb_dmxdev_release(&as102_dev->dvb_dmxdev);
 380         dvb_dmx_release(&as102_dev->dvb_dmx);
 381 
 382         /* unregister dvb adapter */
 383         dvb_unregister_adapter(&as102_dev->dvb_adap);
 384 
 385         pr_info("Unregistered device %s", as102_dev->name);
 386 }
 387 
 388 module_usb_driver(as102_usb_driver);
 389 
 390 /* modinfo details */
 391 MODULE_DESCRIPTION(DRIVER_FULL_NAME);
 392 MODULE_LICENSE("GPL");
 393 MODULE_AUTHOR("Pierrick Hascoet <pierrick.hascoet@abilis.com>");

/* [<][>][^][v][top][bottom][index][help] */