linux/drivers/media/usb/au0828/au0828-dvb.c
<<
>>
Prefs
   1/*
   2 *  Driver for the Auvitek USB bridge
   3 *
   4 *  Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
   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 of the License, or
   9 *  (at your option) 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 *
  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 "au0828.h"
  23
  24#include <linux/module.h>
  25#include <linux/slab.h>
  26#include <linux/init.h>
  27#include <linux/device.h>
  28#include <media/v4l2-common.h>
  29#include <media/tuner.h>
  30
  31#include "au8522.h"
  32#include "xc5000.h"
  33#include "mxl5007t.h"
  34#include "tda18271.h"
  35
  36static int preallocate_big_buffers;
  37module_param_named(preallocate_big_buffers, preallocate_big_buffers, int, 0644);
  38MODULE_PARM_DESC(preallocate_big_buffers, "Preallocate the larger transfer buffers at module load time");
  39
  40DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
  41
  42#define _AU0828_BULKPIPE 0x83
  43#define _BULKPIPESIZE 0xe522
  44
  45static u8 hauppauge_hvr950q_led_states[] = {
  46        0x00, /* off */
  47        0x02, /* yellow */
  48        0x04, /* green */
  49};
  50
  51static struct au8522_led_config hauppauge_hvr950q_led_cfg = {
  52        .gpio_output = 0x00e0,
  53        .gpio_output_enable  = 0x6006,
  54        .gpio_output_disable = 0x0660,
  55
  56        .gpio_leds = 0x00e2,
  57        .led_states  = hauppauge_hvr950q_led_states,
  58        .num_led_states = sizeof(hauppauge_hvr950q_led_states),
  59
  60        .vsb8_strong   = 20 /* dB */ * 10,
  61        .qam64_strong  = 25 /* dB */ * 10,
  62        .qam256_strong = 32 /* dB */ * 10,
  63};
  64
  65static struct au8522_config hauppauge_hvr950q_config = {
  66        .demod_address = 0x8e >> 1,
  67        .status_mode   = AU8522_DEMODLOCKING,
  68        .qam_if        = AU8522_IF_6MHZ,
  69        .vsb_if        = AU8522_IF_6MHZ,
  70        .led_cfg       = &hauppauge_hvr950q_led_cfg,
  71};
  72
  73static struct au8522_config fusionhdtv7usb_config = {
  74        .demod_address = 0x8e >> 1,
  75        .status_mode   = AU8522_DEMODLOCKING,
  76        .qam_if        = AU8522_IF_6MHZ,
  77        .vsb_if        = AU8522_IF_6MHZ,
  78};
  79
  80static struct au8522_config hauppauge_woodbury_config = {
  81        .demod_address = 0x8e >> 1,
  82        .status_mode   = AU8522_DEMODLOCKING,
  83        .qam_if        = AU8522_IF_4MHZ,
  84        .vsb_if        = AU8522_IF_3_25MHZ,
  85};
  86
  87static struct xc5000_config hauppauge_xc5000a_config = {
  88        .i2c_address      = 0x61,
  89        .if_khz           = 6000,
  90        .chip_id          = XC5000A,
  91        .output_amp       = 0x8f,
  92};
  93
  94static struct xc5000_config hauppauge_xc5000c_config = {
  95        .i2c_address      = 0x61,
  96        .if_khz           = 6000,
  97        .chip_id          = XC5000C,
  98        .output_amp       = 0x8f,
  99};
 100
 101static struct mxl5007t_config mxl5007t_hvr950q_config = {
 102        .xtal_freq_hz = MxL_XTAL_24_MHZ,
 103        .if_freq_hz = MxL_IF_6_MHZ,
 104};
 105
 106static struct tda18271_config hauppauge_woodbury_tunerconfig = {
 107        .gate    = TDA18271_GATE_DIGITAL,
 108};
 109
 110static void au0828_restart_dvb_streaming(struct work_struct *work);
 111
 112/*-------------------------------------------------------------------*/
 113static void urb_completion(struct urb *purb)
 114{
 115        struct au0828_dev *dev = purb->context;
 116        int ptype = usb_pipetype(purb->pipe);
 117        unsigned char *ptr;
 118
 119        dprintk(2, "%s: %d\n", __func__, purb->actual_length);
 120
 121        if (!dev) {
 122                dprintk(2, "%s: no dev!\n", __func__);
 123                return;
 124        }
 125
 126        if (!dev->urb_streaming) {
 127                dprintk(2, "%s: not streaming!\n", __func__);
 128                return;
 129        }
 130
 131        if (ptype != PIPE_BULK) {
 132                pr_err("%s: Unsupported URB type %d\n",
 133                       __func__, ptype);
 134                return;
 135        }
 136
 137        /* See if the stream is corrupted (to work around a hardware
 138           bug where the stream gets misaligned */
 139        ptr = purb->transfer_buffer;
 140        if (purb->actual_length > 0 && ptr[0] != 0x47) {
 141                dprintk(1, "Need to restart streaming %02x len=%d!\n",
 142                        ptr[0], purb->actual_length);
 143                schedule_work(&dev->restart_streaming);
 144                return;
 145        }
 146
 147        /* Feed the transport payload into the kernel demux */
 148        dvb_dmx_swfilter_packets(&dev->dvb.demux,
 149                purb->transfer_buffer, purb->actual_length / 188);
 150
 151        /* Clean the buffer before we requeue */
 152        memset(purb->transfer_buffer, 0, URB_BUFSIZE);
 153
 154        /* Requeue URB */
 155        usb_submit_urb(purb, GFP_ATOMIC);
 156}
 157
 158static int stop_urb_transfer(struct au0828_dev *dev)
 159{
 160        int i;
 161
 162        dprintk(2, "%s()\n", __func__);
 163
 164        if (!dev->urb_streaming)
 165                return 0;
 166
 167        dev->urb_streaming = false;
 168        for (i = 0; i < URB_COUNT; i++) {
 169                if (dev->urbs[i]) {
 170                        usb_kill_urb(dev->urbs[i]);
 171                        if (!preallocate_big_buffers)
 172                                kfree(dev->urbs[i]->transfer_buffer);
 173
 174                        usb_free_urb(dev->urbs[i]);
 175                }
 176        }
 177
 178        return 0;
 179}
 180
 181static int start_urb_transfer(struct au0828_dev *dev)
 182{
 183        struct urb *purb;
 184        int i, ret;
 185
 186        dprintk(2, "%s()\n", __func__);
 187
 188        if (dev->urb_streaming) {
 189                dprintk(2, "%s: bulk xfer already running!\n", __func__);
 190                return 0;
 191        }
 192
 193        for (i = 0; i < URB_COUNT; i++) {
 194
 195                dev->urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
 196                if (!dev->urbs[i])
 197                        return -ENOMEM;
 198
 199                purb = dev->urbs[i];
 200
 201                if (preallocate_big_buffers)
 202                        purb->transfer_buffer = dev->dig_transfer_buffer[i];
 203                else
 204                        purb->transfer_buffer = kzalloc(URB_BUFSIZE,
 205                                        GFP_KERNEL);
 206
 207                if (!purb->transfer_buffer) {
 208                        usb_free_urb(purb);
 209                        dev->urbs[i] = NULL;
 210                        ret = -ENOMEM;
 211                        pr_err("%s: failed big buffer allocation, err = %d\n",
 212                               __func__, ret);
 213                        return ret;
 214                }
 215
 216                purb->status = -EINPROGRESS;
 217                usb_fill_bulk_urb(purb,
 218                                  dev->usbdev,
 219                                  usb_rcvbulkpipe(dev->usbdev,
 220                                        _AU0828_BULKPIPE),
 221                                  purb->transfer_buffer,
 222                                  URB_BUFSIZE,
 223                                  urb_completion,
 224                                  dev);
 225
 226        }
 227
 228        for (i = 0; i < URB_COUNT; i++) {
 229                ret = usb_submit_urb(dev->urbs[i], GFP_ATOMIC);
 230                if (ret != 0) {
 231                        stop_urb_transfer(dev);
 232                        pr_err("%s: failed urb submission, err = %d\n",
 233                               __func__, ret);
 234                        return ret;
 235                }
 236        }
 237
 238        dev->urb_streaming = true;
 239        return 0;
 240}
 241
 242static void au0828_start_transport(struct au0828_dev *dev)
 243{
 244        au0828_write(dev, 0x608, 0x90);
 245        au0828_write(dev, 0x609, 0x72);
 246        au0828_write(dev, 0x60a, 0x71);
 247        au0828_write(dev, 0x60b, 0x01);
 248
 249}
 250
 251static void au0828_stop_transport(struct au0828_dev *dev, int full_stop)
 252{
 253        if (full_stop) {
 254                au0828_write(dev, 0x608, 0x00);
 255                au0828_write(dev, 0x609, 0x00);
 256                au0828_write(dev, 0x60a, 0x00);
 257        }
 258        au0828_write(dev, 0x60b, 0x00);
 259}
 260
 261static int au0828_dvb_start_feed(struct dvb_demux_feed *feed)
 262{
 263        struct dvb_demux *demux = feed->demux;
 264        struct au0828_dev *dev = (struct au0828_dev *) demux->priv;
 265        struct au0828_dvb *dvb = &dev->dvb;
 266        int ret = 0;
 267
 268        dprintk(1, "%s()\n", __func__);
 269
 270        if (!demux->dmx.frontend)
 271                return -EINVAL;
 272
 273        if (dvb->frontend) {
 274                mutex_lock(&dvb->lock);
 275                dvb->start_count++;
 276                dprintk(1, "%s(), start_count: %d, stop_count: %d\n", __func__,
 277                        dvb->start_count, dvb->stop_count);
 278                if (dvb->feeding++ == 0) {
 279                        /* Start transport */
 280                        au0828_start_transport(dev);
 281                        ret = start_urb_transfer(dev);
 282                        if (ret < 0) {
 283                                au0828_stop_transport(dev, 0);
 284                                dvb->feeding--; /* We ran out of memory... */
 285                        }
 286                }
 287                mutex_unlock(&dvb->lock);
 288        }
 289
 290        return ret;
 291}
 292
 293static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed)
 294{
 295        struct dvb_demux *demux = feed->demux;
 296        struct au0828_dev *dev = (struct au0828_dev *) demux->priv;
 297        struct au0828_dvb *dvb = &dev->dvb;
 298        int ret = 0;
 299
 300        dprintk(1, "%s()\n", __func__);
 301
 302        if (dvb->frontend) {
 303                cancel_work_sync(&dev->restart_streaming);
 304
 305                mutex_lock(&dvb->lock);
 306                dvb->stop_count++;
 307                dprintk(1, "%s(), start_count: %d, stop_count: %d\n", __func__,
 308                        dvb->start_count, dvb->stop_count);
 309                if (dvb->feeding > 0) {
 310                        dvb->feeding--;
 311                        if (dvb->feeding == 0) {
 312                                /* Stop transport */
 313                                ret = stop_urb_transfer(dev);
 314                                au0828_stop_transport(dev, 0);
 315                        }
 316                }
 317                mutex_unlock(&dvb->lock);
 318        }
 319
 320        return ret;
 321}
 322
 323static void au0828_restart_dvb_streaming(struct work_struct *work)
 324{
 325        struct au0828_dev *dev = container_of(work, struct au0828_dev,
 326                                              restart_streaming);
 327        struct au0828_dvb *dvb = &dev->dvb;
 328
 329        if (!dev->urb_streaming)
 330                return;
 331
 332        dprintk(1, "Restarting streaming...!\n");
 333
 334        mutex_lock(&dvb->lock);
 335
 336        /* Stop transport */
 337        stop_urb_transfer(dev);
 338        au0828_stop_transport(dev, 1);
 339
 340        /* Start transport */
 341        au0828_start_transport(dev);
 342        start_urb_transfer(dev);
 343
 344        mutex_unlock(&dvb->lock);
 345}
 346
 347static int au0828_set_frontend(struct dvb_frontend *fe)
 348{
 349        struct au0828_dev *dev = fe->dvb->priv;
 350        struct au0828_dvb *dvb = &dev->dvb;
 351        int ret, was_streaming;
 352
 353        mutex_lock(&dvb->lock);
 354        was_streaming = dev->urb_streaming;
 355        if (was_streaming) {
 356                au0828_stop_transport(dev, 1);
 357
 358                /*
 359                 * We can't hold a mutex here, as the restart_streaming
 360                 * kthread may also hold it.
 361                 */
 362                mutex_unlock(&dvb->lock);
 363                cancel_work_sync(&dev->restart_streaming);
 364                mutex_lock(&dvb->lock);
 365
 366                stop_urb_transfer(dev);
 367        }
 368        mutex_unlock(&dvb->lock);
 369
 370        ret = dvb->set_frontend(fe);
 371
 372        if (was_streaming) {
 373                mutex_lock(&dvb->lock);
 374                au0828_start_transport(dev);
 375                start_urb_transfer(dev);
 376                mutex_unlock(&dvb->lock);
 377        }
 378
 379        return ret;
 380}
 381
 382static int dvb_register(struct au0828_dev *dev)
 383{
 384        struct au0828_dvb *dvb = &dev->dvb;
 385        int result;
 386
 387        dprintk(1, "%s()\n", __func__);
 388
 389        if (preallocate_big_buffers) {
 390                int i;
 391                for (i = 0; i < URB_COUNT; i++) {
 392                        dev->dig_transfer_buffer[i] = kzalloc(URB_BUFSIZE,
 393                                        GFP_KERNEL);
 394
 395                        if (!dev->dig_transfer_buffer[i]) {
 396                                result = -ENOMEM;
 397
 398                                pr_err("failed buffer allocation (errno = %d)\n",
 399                                       result);
 400                                goto fail_adapter;
 401                        }
 402                }
 403        }
 404
 405        INIT_WORK(&dev->restart_streaming, au0828_restart_dvb_streaming);
 406
 407        /* register adapter */
 408        result = dvb_register_adapter(&dvb->adapter,
 409                                      KBUILD_MODNAME, THIS_MODULE,
 410                                      &dev->usbdev->dev, adapter_nr);
 411        if (result < 0) {
 412                pr_err("dvb_register_adapter failed (errno = %d)\n",
 413                       result);
 414                goto fail_adapter;
 415        }
 416
 417#ifdef CONFIG_MEDIA_CONTROLLER_DVB
 418        dvb->adapter.mdev = dev->media_dev;
 419#endif
 420
 421        dvb->adapter.priv = dev;
 422
 423        /* register frontend */
 424        result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
 425        if (result < 0) {
 426                pr_err("dvb_register_frontend failed (errno = %d)\n",
 427                       result);
 428                goto fail_frontend;
 429        }
 430
 431        /* Hook dvb frontend */
 432        dvb->set_frontend = dvb->frontend->ops.set_frontend;
 433        dvb->frontend->ops.set_frontend = au0828_set_frontend;
 434
 435        /* register demux stuff */
 436        dvb->demux.dmx.capabilities =
 437                DMX_TS_FILTERING | DMX_SECTION_FILTERING |
 438                DMX_MEMORY_BASED_FILTERING;
 439        dvb->demux.priv       = dev;
 440        dvb->demux.filternum  = 256;
 441        dvb->demux.feednum    = 256;
 442        dvb->demux.start_feed = au0828_dvb_start_feed;
 443        dvb->demux.stop_feed  = au0828_dvb_stop_feed;
 444        result = dvb_dmx_init(&dvb->demux);
 445        if (result < 0) {
 446                pr_err("dvb_dmx_init failed (errno = %d)\n", result);
 447                goto fail_dmx;
 448        }
 449
 450        dvb->dmxdev.filternum    = 256;
 451        dvb->dmxdev.demux        = &dvb->demux.dmx;
 452        dvb->dmxdev.capabilities = 0;
 453        result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
 454        if (result < 0) {
 455                pr_err("dvb_dmxdev_init failed (errno = %d)\n", result);
 456                goto fail_dmxdev;
 457        }
 458
 459        dvb->fe_hw.source = DMX_FRONTEND_0;
 460        result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
 461        if (result < 0) {
 462                pr_err("add_frontend failed (DMX_FRONTEND_0, errno = %d)\n",
 463                       result);
 464                goto fail_fe_hw;
 465        }
 466
 467        dvb->fe_mem.source = DMX_MEMORY_FE;
 468        result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
 469        if (result < 0) {
 470                pr_err("add_frontend failed (DMX_MEMORY_FE, errno = %d)\n",
 471                       result);
 472                goto fail_fe_mem;
 473        }
 474
 475        result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
 476        if (result < 0) {
 477                pr_err("connect_frontend failed (errno = %d)\n", result);
 478                goto fail_fe_conn;
 479        }
 480
 481        /* register network adapter */
 482        dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
 483
 484        dvb->start_count = 0;
 485        dvb->stop_count = 0;
 486
 487        result = dvb_create_media_graph(&dvb->adapter, false);
 488        if (result < 0)
 489                goto fail_create_graph;
 490
 491        return 0;
 492
 493fail_create_graph:
 494        dvb_net_release(&dvb->net);
 495fail_fe_conn:
 496        dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
 497fail_fe_mem:
 498        dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
 499fail_fe_hw:
 500        dvb_dmxdev_release(&dvb->dmxdev);
 501fail_dmxdev:
 502        dvb_dmx_release(&dvb->demux);
 503fail_dmx:
 504        dvb_unregister_frontend(dvb->frontend);
 505fail_frontend:
 506        dvb_frontend_detach(dvb->frontend);
 507        dvb_unregister_adapter(&dvb->adapter);
 508fail_adapter:
 509
 510        if (preallocate_big_buffers) {
 511                int i;
 512                for (i = 0; i < URB_COUNT; i++)
 513                        kfree(dev->dig_transfer_buffer[i]);
 514        }
 515
 516        return result;
 517}
 518
 519void au0828_dvb_unregister(struct au0828_dev *dev)
 520{
 521        struct au0828_dvb *dvb = &dev->dvb;
 522
 523        dprintk(1, "%s()\n", __func__);
 524
 525        if (dvb->frontend == NULL)
 526                return;
 527
 528        cancel_work_sync(&dev->restart_streaming);
 529
 530        dvb_net_release(&dvb->net);
 531        dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
 532        dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
 533        dvb_dmxdev_release(&dvb->dmxdev);
 534        dvb_dmx_release(&dvb->demux);
 535        dvb_unregister_frontend(dvb->frontend);
 536        dvb_frontend_detach(dvb->frontend);
 537        dvb_unregister_adapter(&dvb->adapter);
 538
 539        if (preallocate_big_buffers) {
 540                int i;
 541                for (i = 0; i < URB_COUNT; i++)
 542                        kfree(dev->dig_transfer_buffer[i]);
 543        }
 544        dvb->frontend = NULL;
 545}
 546
 547/* All the DVB attach calls go here, this function get's modified
 548 * for each new card. No other function in this file needs
 549 * to change.
 550 */
 551int au0828_dvb_register(struct au0828_dev *dev)
 552{
 553        struct au0828_dvb *dvb = &dev->dvb;
 554        int ret;
 555
 556        dprintk(1, "%s()\n", __func__);
 557
 558        /* init frontend */
 559        switch (dev->boardnr) {
 560        case AU0828_BOARD_HAUPPAUGE_HVR850:
 561        case AU0828_BOARD_HAUPPAUGE_HVR950Q:
 562                dvb->frontend = dvb_attach(au8522_attach,
 563                                &hauppauge_hvr950q_config,
 564                                &dev->i2c_adap);
 565                if (dvb->frontend != NULL)
 566                        switch (dev->board.tuner_type) {
 567                        default:
 568                        case TUNER_XC5000:
 569                                dvb_attach(xc5000_attach, dvb->frontend,
 570                                           &dev->i2c_adap,
 571                                           &hauppauge_xc5000a_config);
 572                                break;
 573                        case TUNER_XC5000C:
 574                                dvb_attach(xc5000_attach, dvb->frontend,
 575                                           &dev->i2c_adap,
 576                                           &hauppauge_xc5000c_config);
 577                                break;
 578                        }
 579                break;
 580        case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
 581                dvb->frontend = dvb_attach(au8522_attach,
 582                                &hauppauge_hvr950q_config,
 583                                &dev->i2c_adap);
 584                if (dvb->frontend != NULL)
 585                        dvb_attach(mxl5007t_attach, dvb->frontend,
 586                                   &dev->i2c_adap, 0x60,
 587                                   &mxl5007t_hvr950q_config);
 588                break;
 589        case AU0828_BOARD_HAUPPAUGE_WOODBURY:
 590                dvb->frontend = dvb_attach(au8522_attach,
 591                                &hauppauge_woodbury_config,
 592                                &dev->i2c_adap);
 593                if (dvb->frontend != NULL)
 594                        dvb_attach(tda18271_attach, dvb->frontend,
 595                                   0x60, &dev->i2c_adap,
 596                                   &hauppauge_woodbury_tunerconfig);
 597                break;
 598        case AU0828_BOARD_DVICO_FUSIONHDTV7:
 599                dvb->frontend = dvb_attach(au8522_attach,
 600                                &fusionhdtv7usb_config,
 601                                &dev->i2c_adap);
 602                if (dvb->frontend != NULL) {
 603                        dvb_attach(xc5000_attach, dvb->frontend,
 604                                &dev->i2c_adap,
 605                                &hauppauge_xc5000a_config);
 606                }
 607                break;
 608        default:
 609                pr_warn("The frontend of your DVB/ATSC card isn't supported yet\n");
 610                break;
 611        }
 612        if (NULL == dvb->frontend) {
 613                pr_err("%s() Frontend initialization failed\n",
 614                       __func__);
 615                return -1;
 616        }
 617        /* define general-purpose callback pointer */
 618        dvb->frontend->callback = au0828_tuner_callback;
 619
 620        /* register everything */
 621        ret = dvb_register(dev);
 622        if (ret < 0) {
 623                if (dvb->frontend->ops.release)
 624                        dvb->frontend->ops.release(dvb->frontend);
 625                dvb->frontend = NULL;
 626                return ret;
 627        }
 628
 629        return 0;
 630}
 631
 632void au0828_dvb_suspend(struct au0828_dev *dev)
 633{
 634        struct au0828_dvb *dvb = &dev->dvb;
 635        int rc;
 636
 637        if (dvb->frontend) {
 638                if (dev->urb_streaming) {
 639                        cancel_work_sync(&dev->restart_streaming);
 640                        /* Stop transport */
 641                        mutex_lock(&dvb->lock);
 642                        stop_urb_transfer(dev);
 643                        au0828_stop_transport(dev, 1);
 644                        mutex_unlock(&dvb->lock);
 645                        dev->need_urb_start = true;
 646                }
 647                /* suspend frontend - does tuner and fe to sleep */
 648                rc = dvb_frontend_suspend(dvb->frontend);
 649                pr_info("au0828_dvb_suspend(): Suspending DVB fe %d\n", rc);
 650        }
 651}
 652
 653void au0828_dvb_resume(struct au0828_dev *dev)
 654{
 655        struct au0828_dvb *dvb = &dev->dvb;
 656        int rc;
 657
 658        if (dvb->frontend) {
 659                /* resume frontend - does fe and tuner init */
 660                rc = dvb_frontend_resume(dvb->frontend);
 661                pr_info("au0828_dvb_resume(): Resuming DVB fe %d\n", rc);
 662                if (dev->need_urb_start) {
 663                        /* Start transport */
 664                        mutex_lock(&dvb->lock);
 665                        au0828_start_transport(dev);
 666                        start_urb_transfer(dev);
 667                        mutex_unlock(&dvb->lock);
 668                }
 669        }
 670}
 671