linux/drivers/media/video/em28xx/em28xx-dvb.c
<<
>>
Prefs
   1/*
   2 DVB device driver for em28xx
   3
   4 (c) 2008 Mauro Carvalho Chehab <mchehab@infradead.org>
   5
   6 (c) 2008 Devin Heitmueller <devin.heitmueller@gmail.com>
   7        - Fixes for the driver to properly work with HVR-950
   8        - Fixes for the driver to properly work with Pinnacle PCTV HD Pro Stick
   9        - Fixes for the driver to properly work with AMD ATI TV Wonder HD 600
  10
  11 (c) 2008 Aidan Thornton <makosoft@googlemail.com>
  12
  13 Based on cx88-dvb, saa7134-dvb and videobuf-dvb originally written by:
  14        (c) 2004, 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au>
  15        (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
  16
  17 This program is free software; you can redistribute it and/or modify
  18 it under the terms of the GNU General Public License as published by
  19 the Free Software Foundation; either version 2 of the License.
  20 */
  21
  22#include <linux/kernel.h>
  23#include <linux/usb.h>
  24
  25#include "em28xx.h"
  26#include <media/v4l2-common.h>
  27#include <media/videobuf-vmalloc.h>
  28#include <media/tuner.h>
  29#include "tuner-simple.h"
  30
  31#include "lgdt330x.h"
  32#include "zl10353.h"
  33#include "s5h1409.h"
  34#include "mt352.h"
  35#include "mt352_priv.h" /* FIXME */
  36#include "tda1002x.h"
  37
  38MODULE_DESCRIPTION("driver for em28xx based DVB cards");
  39MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
  40MODULE_LICENSE("GPL");
  41
  42static unsigned int debug;
  43module_param(debug, int, 0644);
  44MODULE_PARM_DESC(debug, "enable debug messages [dvb]");
  45
  46DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
  47
  48#define dprintk(level, fmt, arg...) do {                        \
  49if (debug >= level)                                             \
  50        printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->name, ## arg); \
  51} while (0)
  52
  53#define EM28XX_DVB_NUM_BUFS 5
  54#define EM28XX_DVB_MAX_PACKETS 64
  55
  56struct em28xx_dvb {
  57        struct dvb_frontend        *frontend;
  58
  59        /* feed count management */
  60        struct mutex               lock;
  61        int                        nfeeds;
  62
  63        /* general boilerplate stuff */
  64        struct dvb_adapter         adapter;
  65        struct dvb_demux           demux;
  66        struct dmxdev              dmxdev;
  67        struct dmx_frontend        fe_hw;
  68        struct dmx_frontend        fe_mem;
  69        struct dvb_net             net;
  70};
  71
  72
  73static inline void print_err_status(struct em28xx *dev,
  74                                     int packet, int status)
  75{
  76        char *errmsg = "Unknown";
  77
  78        switch (status) {
  79        case -ENOENT:
  80                errmsg = "unlinked synchronuously";
  81                break;
  82        case -ECONNRESET:
  83                errmsg = "unlinked asynchronuously";
  84                break;
  85        case -ENOSR:
  86                errmsg = "Buffer error (overrun)";
  87                break;
  88        case -EPIPE:
  89                errmsg = "Stalled (device not responding)";
  90                break;
  91        case -EOVERFLOW:
  92                errmsg = "Babble (bad cable?)";
  93                break;
  94        case -EPROTO:
  95                errmsg = "Bit-stuff error (bad cable?)";
  96                break;
  97        case -EILSEQ:
  98                errmsg = "CRC/Timeout (could be anything)";
  99                break;
 100        case -ETIME:
 101                errmsg = "Device does not respond";
 102                break;
 103        }
 104        if (packet < 0) {
 105                dprintk(1, "URB status %d [%s].\n", status, errmsg);
 106        } else {
 107                dprintk(1, "URB packet %d, status %d [%s].\n",
 108                        packet, status, errmsg);
 109        }
 110}
 111
 112static inline int dvb_isoc_copy(struct em28xx *dev, struct urb *urb)
 113{
 114        int i;
 115
 116        if (!dev)
 117                return 0;
 118
 119        if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
 120                return 0;
 121
 122        if (urb->status < 0) {
 123                print_err_status(dev, -1, urb->status);
 124                if (urb->status == -ENOENT)
 125                        return 0;
 126        }
 127
 128        for (i = 0; i < urb->number_of_packets; i++) {
 129                int status = urb->iso_frame_desc[i].status;
 130
 131                if (status < 0) {
 132                        print_err_status(dev, i, status);
 133                        if (urb->iso_frame_desc[i].status != -EPROTO)
 134                                continue;
 135                }
 136
 137                dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer +
 138                                 urb->iso_frame_desc[i].offset,
 139                                 urb->iso_frame_desc[i].actual_length);
 140        }
 141
 142        return 0;
 143}
 144
 145static int start_streaming(struct em28xx_dvb *dvb)
 146{
 147        int rc;
 148        struct em28xx *dev = dvb->adapter.priv;
 149        int max_dvb_packet_size;
 150
 151        usb_set_interface(dev->udev, 0, 1);
 152        rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
 153        if (rc < 0)
 154                return rc;
 155
 156        max_dvb_packet_size = em28xx_isoc_dvb_max_packetsize(dev);
 157
 158        return em28xx_init_isoc(dev, EM28XX_DVB_MAX_PACKETS,
 159                                EM28XX_DVB_NUM_BUFS, max_dvb_packet_size,
 160                                dvb_isoc_copy);
 161}
 162
 163static int stop_streaming(struct em28xx_dvb *dvb)
 164{
 165        struct em28xx *dev = dvb->adapter.priv;
 166
 167        em28xx_uninit_isoc(dev);
 168
 169        em28xx_set_mode(dev, EM28XX_SUSPEND);
 170
 171        return 0;
 172}
 173
 174static int start_feed(struct dvb_demux_feed *feed)
 175{
 176        struct dvb_demux *demux  = feed->demux;
 177        struct em28xx_dvb *dvb = demux->priv;
 178        int rc, ret;
 179
 180        if (!demux->dmx.frontend)
 181                return -EINVAL;
 182
 183        mutex_lock(&dvb->lock);
 184        dvb->nfeeds++;
 185        rc = dvb->nfeeds;
 186
 187        if (dvb->nfeeds == 1) {
 188                ret = start_streaming(dvb);
 189                if (ret < 0)
 190                        rc = ret;
 191        }
 192
 193        mutex_unlock(&dvb->lock);
 194        return rc;
 195}
 196
 197static int stop_feed(struct dvb_demux_feed *feed)
 198{
 199        struct dvb_demux *demux  = feed->demux;
 200        struct em28xx_dvb *dvb = demux->priv;
 201        int err = 0;
 202
 203        mutex_lock(&dvb->lock);
 204        dvb->nfeeds--;
 205
 206        if (0 == dvb->nfeeds)
 207                err = stop_streaming(dvb);
 208
 209        mutex_unlock(&dvb->lock);
 210        return err;
 211}
 212
 213
 214
 215/* ------------------------------------------------------------------ */
 216static int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
 217{
 218        struct em28xx *dev = fe->dvb->priv;
 219
 220        if (acquire)
 221                return em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
 222        else
 223                return em28xx_set_mode(dev, EM28XX_SUSPEND);
 224}
 225
 226/* ------------------------------------------------------------------ */
 227
 228static struct lgdt330x_config em2880_lgdt3303_dev = {
 229        .demod_address = 0x0e,
 230        .demod_chip = LGDT3303,
 231};
 232
 233static struct zl10353_config em28xx_zl10353_with_xc3028 = {
 234        .demod_address = (0x1e >> 1),
 235        .no_tuner = 1,
 236        .parallel_ts = 1,
 237        .if2 = 45600,
 238};
 239
 240static struct s5h1409_config em28xx_s5h1409_with_xc3028 = {
 241        .demod_address = 0x32 >> 1,
 242        .output_mode   = S5H1409_PARALLEL_OUTPUT,
 243        .gpio          = S5H1409_GPIO_OFF,
 244        .inversion     = S5H1409_INVERSION_OFF,
 245        .status_mode   = S5H1409_DEMODLOCKING,
 246        .mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK
 247};
 248
 249static struct zl10353_config em28xx_zl10353_xc3028_no_i2c_gate = {
 250        .demod_address = (0x1e >> 1),
 251        .no_tuner = 1,
 252        .disable_i2c_gate_ctrl = 1,
 253        .parallel_ts = 1,
 254        .if2 = 45600,
 255};
 256
 257#ifdef EM28XX_DRX397XD_SUPPORT
 258/* [TODO] djh - not sure yet what the device config needs to contain */
 259static struct drx397xD_config em28xx_drx397xD_with_xc3028 = {
 260        .demod_address = (0xe0 >> 1),
 261};
 262#endif
 263
 264static int mt352_terratec_xs_init(struct dvb_frontend *fe)
 265{
 266        /* Values extracted from a USB trace of the Terratec Windows driver */
 267        static u8 clock_config[]   = { CLOCK_CTL,  0x38, 0x2c };
 268        static u8 reset[]          = { RESET,      0x80 };
 269        static u8 adc_ctl_1_cfg[]  = { ADC_CTL_1,  0x40 };
 270        static u8 agc_cfg[]        = { AGC_TARGET, 0x28, 0xa0 };
 271        static u8 input_freq_cfg[] = { INPUT_FREQ_1, 0x31, 0xb8 };
 272        static u8 rs_err_cfg[]     = { RS_ERR_PER_1, 0x00, 0x4d };
 273        static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
 274        static u8 trl_nom_cfg[]    = { TRL_NOMINAL_RATE_1, 0x64, 0x00 };
 275        static u8 tps_given_cfg[]  = { TPS_GIVEN_1, 0x40, 0x80, 0x50 };
 276        static u8 tuner_go[]       = { TUNER_GO, 0x01};
 277
 278        mt352_write(fe, clock_config,   sizeof(clock_config));
 279        udelay(200);
 280        mt352_write(fe, reset,          sizeof(reset));
 281        mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
 282        mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
 283        mt352_write(fe, input_freq_cfg, sizeof(input_freq_cfg));
 284        mt352_write(fe, rs_err_cfg,     sizeof(rs_err_cfg));
 285        mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
 286        mt352_write(fe, trl_nom_cfg,    sizeof(trl_nom_cfg));
 287        mt352_write(fe, tps_given_cfg,  sizeof(tps_given_cfg));
 288        mt352_write(fe, tuner_go,       sizeof(tuner_go));
 289        return 0;
 290}
 291
 292static struct mt352_config terratec_xs_mt352_cfg = {
 293        .demod_address = (0x1e >> 1),
 294        .no_tuner = 1,
 295        .if2 = 45600,
 296        .demod_init = mt352_terratec_xs_init,
 297};
 298
 299static struct tda10023_config em28xx_tda10023_config = {
 300        .demod_address = 0x0c,
 301        .invert = 1,
 302};
 303
 304/* ------------------------------------------------------------------ */
 305
 306static int attach_xc3028(u8 addr, struct em28xx *dev)
 307{
 308        struct dvb_frontend *fe;
 309        struct xc2028_config cfg;
 310
 311        memset(&cfg, 0, sizeof(cfg));
 312        cfg.i2c_adap  = &dev->i2c_adap;
 313        cfg.i2c_addr  = addr;
 314
 315        if (!dev->dvb->frontend) {
 316                printk(KERN_ERR "%s/2: dvb frontend not attached. "
 317                                "Can't attach xc3028\n",
 318                       dev->name);
 319                return -EINVAL;
 320        }
 321
 322        fe = dvb_attach(xc2028_attach, dev->dvb->frontend, &cfg);
 323        if (!fe) {
 324                printk(KERN_ERR "%s/2: xc3028 attach failed\n",
 325                       dev->name);
 326                dvb_frontend_detach(dev->dvb->frontend);
 327                dev->dvb->frontend = NULL;
 328                return -EINVAL;
 329        }
 330
 331        printk(KERN_INFO "%s/2: xc3028 attached\n", dev->name);
 332
 333        return 0;
 334}
 335
 336/* ------------------------------------------------------------------ */
 337
 338static int register_dvb(struct em28xx_dvb *dvb,
 339                 struct module *module,
 340                 struct em28xx *dev,
 341                 struct device *device)
 342{
 343        int result;
 344
 345        mutex_init(&dvb->lock);
 346
 347        /* register adapter */
 348        result = dvb_register_adapter(&dvb->adapter, dev->name, module, device,
 349                                      adapter_nr);
 350        if (result < 0) {
 351                printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n",
 352                       dev->name, result);
 353                goto fail_adapter;
 354        }
 355
 356        /* Ensure all frontends negotiate bus access */
 357        dvb->frontend->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl;
 358
 359        dvb->adapter.priv = dev;
 360
 361        /* register frontend */
 362        result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
 363        if (result < 0) {
 364                printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n",
 365                       dev->name, result);
 366                goto fail_frontend;
 367        }
 368
 369        /* register demux stuff */
 370        dvb->demux.dmx.capabilities =
 371                DMX_TS_FILTERING | DMX_SECTION_FILTERING |
 372                DMX_MEMORY_BASED_FILTERING;
 373        dvb->demux.priv       = dvb;
 374        dvb->demux.filternum  = 256;
 375        dvb->demux.feednum    = 256;
 376        dvb->demux.start_feed = start_feed;
 377        dvb->demux.stop_feed  = stop_feed;
 378
 379        result = dvb_dmx_init(&dvb->demux);
 380        if (result < 0) {
 381                printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n",
 382                       dev->name, result);
 383                goto fail_dmx;
 384        }
 385
 386        dvb->dmxdev.filternum    = 256;
 387        dvb->dmxdev.demux        = &dvb->demux.dmx;
 388        dvb->dmxdev.capabilities = 0;
 389        result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
 390        if (result < 0) {
 391                printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n",
 392                       dev->name, result);
 393                goto fail_dmxdev;
 394        }
 395
 396        dvb->fe_hw.source = DMX_FRONTEND_0;
 397        result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
 398        if (result < 0) {
 399                printk(KERN_WARNING "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n",
 400                       dev->name, result);
 401                goto fail_fe_hw;
 402        }
 403
 404        dvb->fe_mem.source = DMX_MEMORY_FE;
 405        result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
 406        if (result < 0) {
 407                printk(KERN_WARNING "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n",
 408                       dev->name, result);
 409                goto fail_fe_mem;
 410        }
 411
 412        result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
 413        if (result < 0) {
 414                printk(KERN_WARNING "%s: connect_frontend failed (errno = %d)\n",
 415                       dev->name, result);
 416                goto fail_fe_conn;
 417        }
 418
 419        /* register network adapter */
 420        dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
 421        return 0;
 422
 423fail_fe_conn:
 424        dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
 425fail_fe_mem:
 426        dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
 427fail_fe_hw:
 428        dvb_dmxdev_release(&dvb->dmxdev);
 429fail_dmxdev:
 430        dvb_dmx_release(&dvb->demux);
 431fail_dmx:
 432        dvb_unregister_frontend(dvb->frontend);
 433fail_frontend:
 434        dvb_frontend_detach(dvb->frontend);
 435        dvb_unregister_adapter(&dvb->adapter);
 436fail_adapter:
 437        return result;
 438}
 439
 440static void unregister_dvb(struct em28xx_dvb *dvb)
 441{
 442        dvb_net_release(&dvb->net);
 443        dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
 444        dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
 445        dvb_dmxdev_release(&dvb->dmxdev);
 446        dvb_dmx_release(&dvb->demux);
 447        dvb_unregister_frontend(dvb->frontend);
 448        dvb_frontend_detach(dvb->frontend);
 449        dvb_unregister_adapter(&dvb->adapter);
 450}
 451
 452
 453static int dvb_init(struct em28xx *dev)
 454{
 455        int result = 0;
 456        struct em28xx_dvb *dvb;
 457
 458        if (!dev->board.has_dvb) {
 459                /* This device does not support the extension */
 460                return 0;
 461        }
 462
 463        dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
 464
 465        if (dvb == NULL) {
 466                printk(KERN_INFO "em28xx_dvb: memory allocation failed\n");
 467                return -ENOMEM;
 468        }
 469        dev->dvb = dvb;
 470
 471        em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
 472        /* init frontend */
 473        switch (dev->model) {
 474        case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
 475        case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
 476        case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
 477        case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
 478                dvb->frontend = dvb_attach(lgdt330x_attach,
 479                                           &em2880_lgdt3303_dev,
 480                                           &dev->i2c_adap);
 481                if (attach_xc3028(0x61, dev) < 0) {
 482                        result = -EINVAL;
 483                        goto out_free;
 484                }
 485                break;
 486        case EM2880_BOARD_KWORLD_DVB_310U:
 487                dvb->frontend = dvb_attach(zl10353_attach,
 488                                           &em28xx_zl10353_with_xc3028,
 489                                           &dev->i2c_adap);
 490                if (attach_xc3028(0x61, dev) < 0) {
 491                        result = -EINVAL;
 492                        goto out_free;
 493                }
 494                break;
 495        case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
 496        case EM2880_BOARD_EMPIRE_DUAL_TV:
 497                dvb->frontend = dvb_attach(zl10353_attach,
 498                                           &em28xx_zl10353_xc3028_no_i2c_gate,
 499                                           &dev->i2c_adap);
 500                if (attach_xc3028(0x61, dev) < 0) {
 501                        result = -EINVAL;
 502                        goto out_free;
 503                }
 504                break;
 505        case EM2880_BOARD_TERRATEC_HYBRID_XS:
 506        case EM2881_BOARD_PINNACLE_HYBRID_PRO:
 507                dvb->frontend = dvb_attach(zl10353_attach,
 508                                           &em28xx_zl10353_xc3028_no_i2c_gate,
 509                                           &dev->i2c_adap);
 510                if (dvb->frontend == NULL) {
 511                        /* This board could have either a zl10353 or a mt352.
 512                           If the chip id isn't for zl10353, try mt352 */
 513                        dvb->frontend = dvb_attach(mt352_attach,
 514                                                   &terratec_xs_mt352_cfg,
 515                                                   &dev->i2c_adap);
 516                }
 517
 518                if (attach_xc3028(0x61, dev) < 0) {
 519                        result = -EINVAL;
 520                        goto out_free;
 521                }
 522                break;
 523        case EM2883_BOARD_KWORLD_HYBRID_330U:
 524        case EM2882_BOARD_EVGA_INDTUBE:
 525                dvb->frontend = dvb_attach(s5h1409_attach,
 526                                           &em28xx_s5h1409_with_xc3028,
 527                                           &dev->i2c_adap);
 528                if (attach_xc3028(0x61, dev) < 0) {
 529                        result = -EINVAL;
 530                        goto out_free;
 531                }
 532                break;
 533        case EM2882_BOARD_KWORLD_ATSC_315U:
 534                dvb->frontend = dvb_attach(lgdt330x_attach,
 535                                           &em2880_lgdt3303_dev,
 536                                           &dev->i2c_adap);
 537                if (dvb->frontend != NULL) {
 538                        if (!dvb_attach(simple_tuner_attach, dvb->frontend,
 539                                &dev->i2c_adap, 0x61, TUNER_THOMSON_DTT761X)) {
 540                                result = -EINVAL;
 541                                goto out_free;
 542                        }
 543                }
 544                break;
 545        case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
 546#ifdef EM28XX_DRX397XD_SUPPORT
 547                /* We don't have the config structure properly populated, so
 548                   this is commented out for now */
 549                dvb->frontend = dvb_attach(drx397xD_attach,
 550                                           &em28xx_drx397xD_with_xc3028,
 551                                           &dev->i2c_adap);
 552                if (attach_xc3028(0x61, dev) < 0) {
 553                        result = -EINVAL;
 554                        goto out_free;
 555                }
 556                break;
 557#endif
 558        case EM2870_BOARD_REDDO_DVB_C_USB_BOX:
 559                /* Philips CU1216L NIM (Philips TDA10023 + Infineon TUA6034) */
 560                dvb->frontend = dvb_attach(tda10023_attach,
 561                        &em28xx_tda10023_config,
 562                        &dev->i2c_adap, 0x48);
 563                if (dvb->frontend) {
 564                        if (!dvb_attach(simple_tuner_attach, dvb->frontend,
 565                                &dev->i2c_adap, 0x60, TUNER_PHILIPS_CU1216L)) {
 566                                result = -EINVAL;
 567                                goto out_free;
 568                        }
 569                }
 570                break;
 571        default:
 572                printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card"
 573                                " isn't supported yet\n",
 574                       dev->name);
 575                break;
 576        }
 577        if (NULL == dvb->frontend) {
 578                printk(KERN_ERR
 579                       "%s/2: frontend initialization failed\n",
 580                       dev->name);
 581                result = -EINVAL;
 582                goto out_free;
 583        }
 584        /* define general-purpose callback pointer */
 585        dvb->frontend->callback = em28xx_tuner_callback;
 586
 587        /* register everything */
 588        result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev);
 589
 590        if (result < 0)
 591                goto out_free;
 592
 593        em28xx_set_mode(dev, EM28XX_SUSPEND);
 594        printk(KERN_INFO "Successfully loaded em28xx-dvb\n");
 595        return 0;
 596
 597out_free:
 598        em28xx_set_mode(dev, EM28XX_SUSPEND);
 599        kfree(dvb);
 600        dev->dvb = NULL;
 601        return result;
 602}
 603
 604static int dvb_fini(struct em28xx *dev)
 605{
 606        if (!dev->board.has_dvb) {
 607                /* This device does not support the extension */
 608                return 0;
 609        }
 610
 611        if (dev->dvb) {
 612                unregister_dvb(dev->dvb);
 613                dev->dvb = NULL;
 614        }
 615
 616        return 0;
 617}
 618
 619static struct em28xx_ops dvb_ops = {
 620        .id   = EM28XX_DVB,
 621        .name = "Em28xx dvb Extension",
 622        .init = dvb_init,
 623        .fini = dvb_fini,
 624};
 625
 626static int __init em28xx_dvb_register(void)
 627{
 628        return em28xx_register_extension(&dvb_ops);
 629}
 630
 631static void __exit em28xx_dvb_unregister(void)
 632{
 633        em28xx_unregister_extension(&dvb_ops);
 634}
 635
 636module_init(em28xx_dvb_register);
 637module_exit(em28xx_dvb_unregister);
 638