linux/drivers/media/video/cx231xx/cx231xx-dvb.c
<<
>>
Prefs
   1/*
   2 DVB device driver for cx231xx
   3
   4 Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
   5                Based on em28xx driver
   6
   7 This program is free software; you can redistribute it and/or modify
   8   it under the terms of the GNU General Public License as published by
   9   the Free Software Foundation; either version 2 of the License, or
  10   (at your option) any later version.
  11
  12   This program is distributed in the hope that it will be useful,
  13   but WITHOUT ANY WARRANTY; without even the implied warranty of
  14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15   GNU General Public License for more details.
  16
  17   You should have received a copy of the GNU General Public License
  18   along with this program; if not, write to the Free Software
  19   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20 */
  21
  22#include <linux/kernel.h>
  23#include <linux/slab.h>
  24#include <linux/usb.h>
  25
  26#include "cx231xx.h"
  27#include <media/v4l2-common.h>
  28#include <media/videobuf-vmalloc.h>
  29
  30#include "xc5000.h"
  31#include "dvb_dummy_fe.h"
  32
  33MODULE_DESCRIPTION("driver for cx231xx based DVB cards");
  34MODULE_AUTHOR("Srinivasa Deevi <srinivasa.deevi@conexant.com>");
  35MODULE_LICENSE("GPL");
  36
  37static unsigned int debug;
  38module_param(debug, int, 0644);
  39MODULE_PARM_DESC(debug, "enable debug messages [dvb]");
  40
  41DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
  42
  43#define dprintk(level, fmt, arg...) do {                        \
  44if (debug >= level)                                             \
  45        printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->name, ## arg); \
  46} while (0)
  47
  48#define CX231XX_DVB_NUM_BUFS 5
  49#define CX231XX_DVB_MAX_PACKETSIZE 564
  50#define CX231XX_DVB_MAX_PACKETS 64
  51
  52struct cx231xx_dvb {
  53        struct dvb_frontend *frontend;
  54
  55        /* feed count management */
  56        struct mutex lock;
  57        int nfeeds;
  58
  59        /* general boilerplate stuff */
  60        struct dvb_adapter adapter;
  61        struct dvb_demux demux;
  62        struct dmxdev dmxdev;
  63        struct dmx_frontend fe_hw;
  64        struct dmx_frontend fe_mem;
  65        struct dvb_net net;
  66};
  67
  68static inline void print_err_status(struct cx231xx *dev, int packet, int status)
  69{
  70        char *errmsg = "Unknown";
  71
  72        switch (status) {
  73        case -ENOENT:
  74                errmsg = "unlinked synchronuously";
  75                break;
  76        case -ECONNRESET:
  77                errmsg = "unlinked asynchronuously";
  78                break;
  79        case -ENOSR:
  80                errmsg = "Buffer error (overrun)";
  81                break;
  82        case -EPIPE:
  83                errmsg = "Stalled (device not responding)";
  84                break;
  85        case -EOVERFLOW:
  86                errmsg = "Babble (bad cable?)";
  87                break;
  88        case -EPROTO:
  89                errmsg = "Bit-stuff error (bad cable?)";
  90                break;
  91        case -EILSEQ:
  92                errmsg = "CRC/Timeout (could be anything)";
  93                break;
  94        case -ETIME:
  95                errmsg = "Device does not respond";
  96                break;
  97        }
  98        if (packet < 0) {
  99                dprintk(1, "URB status %d [%s].\n", status, errmsg);
 100        } else {
 101                dprintk(1, "URB packet %d, status %d [%s].\n",
 102                        packet, status, errmsg);
 103        }
 104}
 105
 106static inline int dvb_isoc_copy(struct cx231xx *dev, struct urb *urb)
 107{
 108        int i;
 109
 110        if (!dev)
 111                return 0;
 112
 113        if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
 114                return 0;
 115
 116        if (urb->status < 0) {
 117                print_err_status(dev, -1, urb->status);
 118                if (urb->status == -ENOENT)
 119                        return 0;
 120        }
 121
 122        for (i = 0; i < urb->number_of_packets; i++) {
 123                int status = urb->iso_frame_desc[i].status;
 124
 125                if (status < 0) {
 126                        print_err_status(dev, i, status);
 127                        if (urb->iso_frame_desc[i].status != -EPROTO)
 128                                continue;
 129                }
 130
 131                dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer +
 132                                 urb->iso_frame_desc[i].offset,
 133                                 urb->iso_frame_desc[i].actual_length);
 134        }
 135
 136        return 0;
 137}
 138
 139static int start_streaming(struct cx231xx_dvb *dvb)
 140{
 141        int rc;
 142        struct cx231xx *dev = dvb->adapter.priv;
 143
 144        usb_set_interface(dev->udev, 0, 1);
 145        rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
 146        if (rc < 0)
 147                return rc;
 148
 149        return cx231xx_init_isoc(dev, CX231XX_DVB_MAX_PACKETS,
 150                                 CX231XX_DVB_NUM_BUFS,
 151                                 CX231XX_DVB_MAX_PACKETSIZE, dvb_isoc_copy);
 152}
 153
 154static int stop_streaming(struct cx231xx_dvb *dvb)
 155{
 156        struct cx231xx *dev = dvb->adapter.priv;
 157
 158        cx231xx_uninit_isoc(dev);
 159
 160        cx231xx_set_mode(dev, CX231XX_SUSPEND);
 161
 162        return 0;
 163}
 164
 165static int start_feed(struct dvb_demux_feed *feed)
 166{
 167        struct dvb_demux *demux = feed->demux;
 168        struct cx231xx_dvb *dvb = demux->priv;
 169        int rc, ret;
 170
 171        if (!demux->dmx.frontend)
 172                return -EINVAL;
 173
 174        mutex_lock(&dvb->lock);
 175        dvb->nfeeds++;
 176        rc = dvb->nfeeds;
 177
 178        if (dvb->nfeeds == 1) {
 179                ret = start_streaming(dvb);
 180                if (ret < 0)
 181                        rc = ret;
 182        }
 183
 184        mutex_unlock(&dvb->lock);
 185        return rc;
 186}
 187
 188static int stop_feed(struct dvb_demux_feed *feed)
 189{
 190        struct dvb_demux *demux = feed->demux;
 191        struct cx231xx_dvb *dvb = demux->priv;
 192        int err = 0;
 193
 194        mutex_lock(&dvb->lock);
 195        dvb->nfeeds--;
 196
 197        if (0 == dvb->nfeeds)
 198                err = stop_streaming(dvb);
 199
 200        mutex_unlock(&dvb->lock);
 201        return err;
 202}
 203
 204/* ------------------------------------------------------------------ */
 205static int cx231xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
 206{
 207        struct cx231xx *dev = fe->dvb->priv;
 208
 209        if (acquire)
 210                return cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
 211        else
 212                return cx231xx_set_mode(dev, CX231XX_SUSPEND);
 213}
 214
 215/* ------------------------------------------------------------------ */
 216
 217static struct xc5000_config cnxt_rde250_tunerconfig = {
 218        .i2c_address = 0x61,
 219        .if_khz = 5380,
 220};
 221
 222/* ------------------------------------------------------------------ */
 223#if 0
 224static int attach_xc5000(u8 addr, struct cx231xx *dev)
 225{
 226
 227        struct dvb_frontend *fe;
 228        struct xc5000_config cfg;
 229
 230        memset(&cfg, 0, sizeof(cfg));
 231        cfg.i2c_adap = &dev->i2c_bus[1].i2c_adap;
 232        cfg.i2c_addr = addr;
 233
 234        if (!dev->dvb->frontend) {
 235                printk(KERN_ERR "%s/2: dvb frontend not attached. "
 236                       "Can't attach xc5000\n", dev->name);
 237                return -EINVAL;
 238        }
 239
 240        fe = dvb_attach(xc5000_attach, dev->dvb->frontend, &cfg);
 241        if (!fe) {
 242                printk(KERN_ERR "%s/2: xc5000 attach failed\n", dev->name);
 243                dvb_frontend_detach(dev->dvb->frontend);
 244                dev->dvb->frontend = NULL;
 245                return -EINVAL;
 246        }
 247
 248        printk(KERN_INFO "%s/2: xc5000 attached\n", dev->name);
 249
 250        return 0;
 251}
 252#endif
 253
 254int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq)
 255{
 256        int status = 0;
 257
 258        if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) {
 259
 260                struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops;
 261
 262                if (dops->set_analog_params != NULL) {
 263                        struct analog_parameters params;
 264
 265                        params.frequency = freq;
 266                        params.std = dev->norm;
 267                        params.mode = 0;        /* 0- Air; 1 - cable */
 268                        /*params.audmode = ;       */
 269
 270                        /* Set the analog parameters to set the frequency */
 271                        cx231xx_info("Setting Frequency for XC5000\n");
 272                        dops->set_analog_params(dev->dvb->frontend, &params);
 273                }
 274
 275        }
 276
 277        return status;
 278}
 279
 280int cx231xx_reset_analog_tuner(struct cx231xx *dev)
 281{
 282        int status = 0;
 283
 284        if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) {
 285
 286                struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops;
 287
 288                if (dops->init != NULL && !dev->xc_fw_load_done) {
 289
 290                        cx231xx_info("Reloading firmware for XC5000\n");
 291                        status = dops->init(dev->dvb->frontend);
 292                        if (status == 0) {
 293                                dev->xc_fw_load_done = 1;
 294                                cx231xx_info
 295                                    ("XC5000 firmware download completed\n");
 296                        } else {
 297                                dev->xc_fw_load_done = 0;
 298                                cx231xx_info
 299                                    ("XC5000 firmware download failed !!!\n");
 300                        }
 301                }
 302
 303        }
 304
 305        return status;
 306}
 307
 308/* ------------------------------------------------------------------ */
 309
 310static int register_dvb(struct cx231xx_dvb *dvb,
 311                        struct module *module,
 312                        struct cx231xx *dev, struct device *device)
 313{
 314        int result;
 315
 316        mutex_init(&dvb->lock);
 317
 318        /* register adapter */
 319        result = dvb_register_adapter(&dvb->adapter, dev->name, module, device,
 320                                      adapter_nr);
 321        if (result < 0) {
 322                printk(KERN_WARNING
 323                       "%s: dvb_register_adapter failed (errno = %d)\n",
 324                       dev->name, result);
 325                goto fail_adapter;
 326        }
 327
 328        /* Ensure all frontends negotiate bus access */
 329        dvb->frontend->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl;
 330
 331        dvb->adapter.priv = dev;
 332
 333        /* register frontend */
 334        result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
 335        if (result < 0) {
 336                printk(KERN_WARNING
 337                       "%s: dvb_register_frontend failed (errno = %d)\n",
 338                       dev->name, result);
 339                goto fail_frontend;
 340        }
 341
 342        /* register demux stuff */
 343        dvb->demux.dmx.capabilities =
 344            DMX_TS_FILTERING | DMX_SECTION_FILTERING |
 345            DMX_MEMORY_BASED_FILTERING;
 346        dvb->demux.priv = dvb;
 347        dvb->demux.filternum = 256;
 348        dvb->demux.feednum = 256;
 349        dvb->demux.start_feed = start_feed;
 350        dvb->demux.stop_feed = stop_feed;
 351
 352        result = dvb_dmx_init(&dvb->demux);
 353        if (result < 0) {
 354                printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n",
 355                       dev->name, result);
 356                goto fail_dmx;
 357        }
 358
 359        dvb->dmxdev.filternum = 256;
 360        dvb->dmxdev.demux = &dvb->demux.dmx;
 361        dvb->dmxdev.capabilities = 0;
 362        result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
 363        if (result < 0) {
 364                printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n",
 365                       dev->name, result);
 366                goto fail_dmxdev;
 367        }
 368
 369        dvb->fe_hw.source = DMX_FRONTEND_0;
 370        result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
 371        if (result < 0) {
 372                printk(KERN_WARNING
 373                       "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n",
 374                       dev->name, result);
 375                goto fail_fe_hw;
 376        }
 377
 378        dvb->fe_mem.source = DMX_MEMORY_FE;
 379        result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
 380        if (result < 0) {
 381                printk(KERN_WARNING
 382                       "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n",
 383                       dev->name, result);
 384                goto fail_fe_mem;
 385        }
 386
 387        result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
 388        if (result < 0) {
 389                printk(KERN_WARNING
 390                       "%s: connect_frontend failed (errno = %d)\n", dev->name,
 391                       result);
 392                goto fail_fe_conn;
 393        }
 394
 395        /* register network adapter */
 396        dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
 397        return 0;
 398
 399fail_fe_conn:
 400        dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
 401fail_fe_mem:
 402        dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
 403fail_fe_hw:
 404        dvb_dmxdev_release(&dvb->dmxdev);
 405fail_dmxdev:
 406        dvb_dmx_release(&dvb->demux);
 407fail_dmx:
 408        dvb_unregister_frontend(dvb->frontend);
 409fail_frontend:
 410        dvb_frontend_detach(dvb->frontend);
 411        dvb_unregister_adapter(&dvb->adapter);
 412fail_adapter:
 413        return result;
 414}
 415
 416static void unregister_dvb(struct cx231xx_dvb *dvb)
 417{
 418        dvb_net_release(&dvb->net);
 419        dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
 420        dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
 421        dvb_dmxdev_release(&dvb->dmxdev);
 422        dvb_dmx_release(&dvb->demux);
 423        dvb_unregister_frontend(dvb->frontend);
 424        dvb_frontend_detach(dvb->frontend);
 425        dvb_unregister_adapter(&dvb->adapter);
 426}
 427
 428static int dvb_init(struct cx231xx *dev)
 429{
 430        int result = 0;
 431        struct cx231xx_dvb *dvb;
 432
 433        if (!dev->board.has_dvb) {
 434                /* This device does not support the extension */
 435                return 0;
 436        }
 437
 438        dvb = kzalloc(sizeof(struct cx231xx_dvb), GFP_KERNEL);
 439
 440        if (dvb == NULL) {
 441                printk(KERN_INFO "cx231xx_dvb: memory allocation failed\n");
 442                return -ENOMEM;
 443        }
 444        dev->dvb = dvb;
 445        dev->cx231xx_set_analog_freq = cx231xx_set_analog_freq;
 446        dev->cx231xx_reset_analog_tuner = cx231xx_reset_analog_tuner;
 447
 448        cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
 449        /* init frontend */
 450        switch (dev->model) {
 451        case CX231XX_BOARD_CNXT_RDE_250:
 452
 453                /* dev->dvb->frontend = dvb_attach(s5h1411_attach,
 454                   &dvico_s5h1411_config,
 455                   &dev->i2c_bus[1].i2c_adap); */
 456                dev->dvb->frontend = dvb_attach(dvb_dummy_fe_ofdm_attach);
 457
 458                if (dev->dvb->frontend == NULL) {
 459                        printk(DRIVER_NAME
 460                               ": Failed to attach dummy front end\n");
 461                        result = -EINVAL;
 462                        goto out_free;
 463                }
 464
 465                /* define general-purpose callback pointer */
 466                dvb->frontend->callback = cx231xx_tuner_callback;
 467
 468                if (!dvb_attach(xc5000_attach, dev->dvb->frontend,
 469                               &dev->i2c_bus[1].i2c_adap,
 470                               &cnxt_rde250_tunerconfig)) {
 471                        result = -EINVAL;
 472                        goto out_free;
 473                }
 474
 475                break;
 476        case CX231XX_BOARD_CNXT_RDU_250:
 477
 478                dev->dvb->frontend = dvb_attach(dvb_dummy_fe_ofdm_attach);
 479
 480                if (dev->dvb->frontend == NULL) {
 481                        printk(DRIVER_NAME
 482                               ": Failed to attach dummy front end\n");
 483                        result = -EINVAL;
 484                        goto out_free;
 485                }
 486
 487                /* define general-purpose callback pointer */
 488                dvb->frontend->callback = cx231xx_tuner_callback;
 489
 490                if (!dvb_attach(xc5000_attach, dev->dvb->frontend,
 491                               &dev->i2c_bus[1].i2c_adap,
 492                               &cnxt_rde250_tunerconfig)) {
 493                        result = -EINVAL;
 494                        goto out_free;
 495                }
 496                break;
 497
 498        default:
 499                printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card"
 500                       " isn't supported yet\n", dev->name);
 501                break;
 502        }
 503        if (NULL == dvb->frontend) {
 504                printk(KERN_ERR
 505                       "%s/2: frontend initialization failed\n", dev->name);
 506                result = -EINVAL;
 507                goto out_free;
 508        }
 509
 510        /* register everything */
 511        result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev);
 512
 513        if (result < 0)
 514                goto out_free;
 515
 516        cx231xx_set_mode(dev, CX231XX_SUSPEND);
 517        printk(KERN_INFO "Successfully loaded cx231xx-dvb\n");
 518        return 0;
 519
 520out_free:
 521        cx231xx_set_mode(dev, CX231XX_SUSPEND);
 522        kfree(dvb);
 523        dev->dvb = NULL;
 524        return result;
 525}
 526
 527static int dvb_fini(struct cx231xx *dev)
 528{
 529        if (!dev->board.has_dvb) {
 530                /* This device does not support the extension */
 531                return 0;
 532        }
 533
 534        if (dev->dvb) {
 535                unregister_dvb(dev->dvb);
 536                dev->dvb = NULL;
 537        }
 538
 539        return 0;
 540}
 541
 542static struct cx231xx_ops dvb_ops = {
 543        .id = CX231XX_DVB,
 544        .name = "Cx231xx dvb Extension",
 545        .init = dvb_init,
 546        .fini = dvb_fini,
 547};
 548
 549static int __init cx231xx_dvb_register(void)
 550{
 551        return cx231xx_register_extension(&dvb_ops);
 552}
 553
 554static void __exit cx231xx_dvb_unregister(void)
 555{
 556        cx231xx_unregister_extension(&dvb_ops);
 557}
 558
 559module_init(cx231xx_dvb_register);
 560module_exit(cx231xx_dvb_unregister);
 561