linux/drivers/media/video/tm6000/tm6000-dvb.c
<<
>>
Prefs
   1/*
   2 *  tm6000-dvb.c - dvb-t support for TM5600/TM6000/TM6010 USB video capture devices
   3 *
   4 *  Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.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 version 2
   9 *
  10 *  This program is distributed in the hope that it will be useful,
  11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 *  GNU General Public License for more details.
  14 *
  15 *  You should have received a copy of the GNU General Public License
  16 *  along with this program; if not, write to the Free Software
  17 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18 */
  19
  20#include <linux/kernel.h>
  21#include <linux/slab.h>
  22#include <linux/usb.h>
  23
  24#include "tm6000.h"
  25#include "tm6000-regs.h"
  26
  27#include "zl10353.h"
  28
  29#include <media/tuner.h>
  30
  31#include "tuner-xc2028.h"
  32#include "xc5000.h"
  33
  34MODULE_DESCRIPTION("DVB driver extension module for tm5600/6000/6010 based TV cards");
  35MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
  36MODULE_LICENSE("GPL");
  37
  38MODULE_SUPPORTED_DEVICE("{{Trident, tm5600},"
  39                        "{{Trident, tm6000},"
  40                        "{{Trident, tm6010}");
  41
  42static int debug;
  43
  44module_param(debug, int, 0644);
  45MODULE_PARM_DESC(debug, "enable debug message");
  46
  47static inline void print_err_status(struct tm6000_core *dev,
  48                                    int packet, int status)
  49{
  50        char *errmsg = "Unknown";
  51
  52        switch (status) {
  53        case -ENOENT:
  54                errmsg = "unlinked synchronuously";
  55                break;
  56        case -ECONNRESET:
  57                errmsg = "unlinked asynchronuously";
  58                break;
  59        case -ENOSR:
  60                errmsg = "Buffer error (overrun)";
  61                break;
  62        case -EPIPE:
  63                errmsg = "Stalled (device not responding)";
  64                break;
  65        case -EOVERFLOW:
  66                errmsg = "Babble (bad cable?)";
  67                break;
  68        case -EPROTO:
  69                errmsg = "Bit-stuff error (bad cable?)";
  70                break;
  71        case -EILSEQ:
  72                errmsg = "CRC/Timeout (could be anything)";
  73                break;
  74        case -ETIME:
  75                errmsg = "Device does not respond";
  76                break;
  77        }
  78        if (packet < 0) {
  79                dprintk(dev, 1, "URB status %d [%s].\n",
  80                        status, errmsg);
  81        } else {
  82                dprintk(dev, 1, "URB packet %d, status %d [%s].\n",
  83                        packet, status, errmsg);
  84        }
  85}
  86
  87static void tm6000_urb_received(struct urb *urb)
  88{
  89        int ret;
  90        struct tm6000_core *dev = urb->context;
  91
  92        if (urb->status != 0)
  93                print_err_status(dev, 0, urb->status);
  94        else if (urb->actual_length > 0)
  95                dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer,
  96                                                   urb->actual_length);
  97
  98        if (dev->dvb->streams > 0) {
  99                ret = usb_submit_urb(urb, GFP_ATOMIC);
 100                if (ret < 0) {
 101                        printk(KERN_ERR "tm6000:  error %s\n", __func__);
 102                        kfree(urb->transfer_buffer);
 103                        usb_free_urb(urb);
 104                }
 105        }
 106}
 107
 108static int tm6000_start_stream(struct tm6000_core *dev)
 109{
 110        int ret;
 111        unsigned int pipe, size;
 112        struct tm6000_dvb *dvb = dev->dvb;
 113
 114        printk(KERN_INFO "tm6000: got start stream request %s\n", __func__);
 115
 116        if (dev->mode != TM6000_MODE_DIGITAL) {
 117                tm6000_init_digital_mode(dev);
 118                dev->mode = TM6000_MODE_DIGITAL;
 119        }
 120
 121        dvb->bulk_urb = usb_alloc_urb(0, GFP_KERNEL);
 122        if (dvb->bulk_urb == NULL) {
 123                printk(KERN_ERR "tm6000: couldn't allocate urb\n");
 124                return -ENOMEM;
 125        }
 126
 127        pipe = usb_rcvbulkpipe(dev->udev, dev->bulk_in.endp->desc.bEndpointAddress
 128                                                          & USB_ENDPOINT_NUMBER_MASK);
 129
 130        size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
 131        size = size * 15; /* 512 x 8 or 12 or 15 */
 132
 133        dvb->bulk_urb->transfer_buffer = kzalloc(size, GFP_KERNEL);
 134        if (dvb->bulk_urb->transfer_buffer == NULL) {
 135                usb_free_urb(dvb->bulk_urb);
 136                printk(KERN_ERR "tm6000: couldn't allocate transfer buffer!\n");
 137                return -ENOMEM;
 138        }
 139
 140        usb_fill_bulk_urb(dvb->bulk_urb, dev->udev, pipe,
 141                                                 dvb->bulk_urb->transfer_buffer,
 142                                                 size,
 143                                                 tm6000_urb_received, dev);
 144
 145        ret = usb_clear_halt(dev->udev, pipe);
 146        if (ret < 0) {
 147                printk(KERN_ERR "tm6000: error %i in %s during pipe reset\n",
 148                                                        ret, __func__);
 149                return ret;
 150        } else
 151                printk(KERN_ERR "tm6000: pipe resetted\n");
 152
 153/*      mutex_lock(&tm6000_driver.open_close_mutex); */
 154        ret = usb_submit_urb(dvb->bulk_urb, GFP_KERNEL);
 155
 156/*      mutex_unlock(&tm6000_driver.open_close_mutex); */
 157        if (ret) {
 158                printk(KERN_ERR "tm6000: submit of urb failed (error=%i)\n",
 159                                                                        ret);
 160
 161                kfree(dvb->bulk_urb->transfer_buffer);
 162                usb_free_urb(dvb->bulk_urb);
 163                return ret;
 164        }
 165
 166        return 0;
 167}
 168
 169static void tm6000_stop_stream(struct tm6000_core *dev)
 170{
 171        struct tm6000_dvb *dvb = dev->dvb;
 172
 173        if (dvb->bulk_urb) {
 174                printk(KERN_INFO "urb killing\n");
 175                usb_kill_urb(dvb->bulk_urb);
 176                printk(KERN_INFO "urb buffer free\n");
 177                kfree(dvb->bulk_urb->transfer_buffer);
 178                usb_free_urb(dvb->bulk_urb);
 179                dvb->bulk_urb = NULL;
 180        }
 181}
 182
 183static int tm6000_start_feed(struct dvb_demux_feed *feed)
 184{
 185        struct dvb_demux *demux = feed->demux;
 186        struct tm6000_core *dev = demux->priv;
 187        struct tm6000_dvb *dvb = dev->dvb;
 188        printk(KERN_INFO "tm6000: got start feed request %s\n", __func__);
 189
 190        mutex_lock(&dvb->mutex);
 191        if (dvb->streams == 0) {
 192                dvb->streams = 1;
 193/*              mutex_init(&tm6000_dev->streming_mutex); */
 194                tm6000_start_stream(dev);
 195        } else
 196                ++(dvb->streams);
 197        mutex_unlock(&dvb->mutex);
 198
 199        return 0;
 200}
 201
 202static int tm6000_stop_feed(struct dvb_demux_feed *feed)
 203{
 204        struct dvb_demux *demux = feed->demux;
 205        struct tm6000_core *dev = demux->priv;
 206        struct tm6000_dvb *dvb = dev->dvb;
 207
 208        printk(KERN_INFO "tm6000: got stop feed request %s\n", __func__);
 209
 210        mutex_lock(&dvb->mutex);
 211
 212        printk(KERN_INFO "stream %#x\n", dvb->streams);
 213        --(dvb->streams);
 214        if (dvb->streams == 0) {
 215                printk(KERN_INFO "stop stream\n");
 216                tm6000_stop_stream(dev);
 217/*              mutex_destroy(&tm6000_dev->streaming_mutex); */
 218        }
 219        mutex_unlock(&dvb->mutex);
 220/*      mutex_destroy(&tm6000_dev->streaming_mutex); */
 221
 222        return 0;
 223}
 224
 225static int tm6000_dvb_attach_frontend(struct tm6000_core *dev)
 226{
 227        struct tm6000_dvb *dvb = dev->dvb;
 228
 229        if (dev->caps.has_zl10353) {
 230                struct zl10353_config config = {
 231                                     .demod_address = dev->demod_addr,
 232                                     .no_tuner = 1,
 233                                     .parallel_ts = 1,
 234                                     .if2 = 45700,
 235                                     .disable_i2c_gate_ctrl = 1,
 236                                    };
 237
 238                dvb->frontend = dvb_attach(zl10353_attach, &config,
 239                                                           &dev->i2c_adap);
 240        } else {
 241                printk(KERN_ERR "tm6000: no frontend defined for the device!\n");
 242                return -1;
 243        }
 244
 245        return (!dvb->frontend) ? -1 : 0;
 246}
 247
 248DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 249
 250static int register_dvb(struct tm6000_core *dev)
 251{
 252        int ret = -1;
 253        struct tm6000_dvb *dvb = dev->dvb;
 254
 255        mutex_init(&dvb->mutex);
 256
 257        dvb->streams = 0;
 258
 259        /* attach the frontend */
 260        ret = tm6000_dvb_attach_frontend(dev);
 261        if (ret < 0) {
 262                printk(KERN_ERR "tm6000: couldn't attach the frontend!\n");
 263                goto err;
 264        }
 265
 266        ret = dvb_register_adapter(&dvb->adapter, "Trident TVMaster 6000 DVB-T",
 267                                        THIS_MODULE, &dev->udev->dev, adapter_nr);
 268        dvb->adapter.priv = dev;
 269
 270        if (dvb->frontend) {
 271                switch (dev->tuner_type) {
 272                case TUNER_XC2028: {
 273                        struct xc2028_config cfg = {
 274                                .i2c_adap = &dev->i2c_adap,
 275                                .i2c_addr = dev->tuner_addr,
 276                        };
 277
 278                        dvb->frontend->callback = tm6000_tuner_callback;
 279                        ret = dvb_register_frontend(&dvb->adapter, dvb->frontend);
 280                        if (ret < 0) {
 281                                printk(KERN_ERR
 282                                        "tm6000: couldn't register frontend\n");
 283                                goto adapter_err;
 284                        }
 285
 286                        if (!dvb_attach(xc2028_attach, dvb->frontend, &cfg)) {
 287                                printk(KERN_ERR "tm6000: couldn't register "
 288                                                "frontend (xc3028)\n");
 289                                ret = -EINVAL;
 290                                goto frontend_err;
 291                        }
 292                        printk(KERN_INFO "tm6000: XC2028/3028 asked to be "
 293                                         "attached to frontend!\n");
 294                        break;
 295                        }
 296                case TUNER_XC5000: {
 297                        struct xc5000_config cfg = {
 298                                .i2c_address = dev->tuner_addr,
 299                        };
 300
 301                        dvb->frontend->callback = tm6000_xc5000_callback;
 302                        ret = dvb_register_frontend(&dvb->adapter, dvb->frontend);
 303                        if (ret < 0) {
 304                                printk(KERN_ERR
 305                                        "tm6000: couldn't register frontend\n");
 306                                goto adapter_err;
 307                        }
 308
 309                        if (!dvb_attach(xc5000_attach, dvb->frontend, &dev->i2c_adap, &cfg)) {
 310                                printk(KERN_ERR "tm6000: couldn't register "
 311                                                "frontend (xc5000)\n");
 312                                ret = -EINVAL;
 313                                goto frontend_err;
 314                        }
 315                        printk(KERN_INFO "tm6000: XC5000 asked to be "
 316                                         "attached to frontend!\n");
 317                        break;
 318                        }
 319                }
 320        } else
 321                printk(KERN_ERR "tm6000: no frontend found\n");
 322
 323        dvb->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING
 324                                                            | DMX_MEMORY_BASED_FILTERING;
 325        dvb->demux.priv = dev;
 326        dvb->demux.filternum = 8;
 327        dvb->demux.feednum = 8;
 328        dvb->demux.start_feed = tm6000_start_feed;
 329        dvb->demux.stop_feed = tm6000_stop_feed;
 330        dvb->demux.write_to_decoder = NULL;
 331        ret = dvb_dmx_init(&dvb->demux);
 332        if (ret < 0) {
 333                printk(KERN_ERR "tm6000: dvb_dmx_init failed (errno = %d)\n", ret);
 334                goto frontend_err;
 335        }
 336
 337        dvb->dmxdev.filternum = dev->dvb->demux.filternum;
 338        dvb->dmxdev.demux = &dev->dvb->demux.dmx;
 339        dvb->dmxdev.capabilities = 0;
 340
 341        ret =  dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
 342        if (ret < 0) {
 343                printk(KERN_ERR "tm6000: dvb_dmxdev_init failed (errno = %d)\n", ret);
 344                goto dvb_dmx_err;
 345        }
 346
 347        return 0;
 348
 349dvb_dmx_err:
 350        dvb_dmx_release(&dvb->demux);
 351frontend_err:
 352        if (dvb->frontend) {
 353                dvb_frontend_detach(dvb->frontend);
 354                dvb_unregister_frontend(dvb->frontend);
 355        }
 356adapter_err:
 357        dvb_unregister_adapter(&dvb->adapter);
 358err:
 359        return ret;
 360}
 361
 362static void unregister_dvb(struct tm6000_core *dev)
 363{
 364        struct tm6000_dvb *dvb = dev->dvb;
 365
 366        if (dvb->bulk_urb != NULL) {
 367                struct urb *bulk_urb = dvb->bulk_urb;
 368
 369                kfree(bulk_urb->transfer_buffer);
 370                bulk_urb->transfer_buffer = NULL;
 371                usb_unlink_urb(bulk_urb);
 372                usb_free_urb(bulk_urb);
 373        }
 374
 375/*      mutex_lock(&tm6000_driver.open_close_mutex); */
 376        if (dvb->frontend) {
 377                dvb_frontend_detach(dvb->frontend);
 378                dvb_unregister_frontend(dvb->frontend);
 379        }
 380
 381        dvb_dmxdev_release(&dvb->dmxdev);
 382        dvb_dmx_release(&dvb->demux);
 383        dvb_unregister_adapter(&dvb->adapter);
 384        mutex_destroy(&dvb->mutex);
 385/*      mutex_unlock(&tm6000_driver.open_close_mutex); */
 386}
 387
 388static int dvb_init(struct tm6000_core *dev)
 389{
 390        struct tm6000_dvb *dvb;
 391        int rc;
 392
 393        if (!dev)
 394                return 0;
 395
 396        if (!dev->caps.has_dvb)
 397                return 0;
 398
 399        dvb = kzalloc(sizeof(struct tm6000_dvb), GFP_KERNEL);
 400        if (!dvb) {
 401                printk(KERN_INFO "Cannot allocate memory\n");
 402                return -ENOMEM;
 403        }
 404
 405        dev->dvb = dvb;
 406
 407        rc = register_dvb(dev);
 408        if (rc < 0) {
 409                kfree(dvb);
 410                dev->dvb = NULL;
 411                return 0;
 412        }
 413
 414        return 0;
 415}
 416
 417static int dvb_fini(struct tm6000_core *dev)
 418{
 419        if (!dev)
 420                return 0;
 421
 422        if (!dev->caps.has_dvb)
 423                return 0;
 424
 425        if (dev->dvb) {
 426                unregister_dvb(dev);
 427                kfree(dev->dvb);
 428                dev->dvb = NULL;
 429        }
 430
 431        return 0;
 432}
 433
 434static struct tm6000_ops dvb_ops = {
 435        .type   = TM6000_DVB,
 436        .name   = "TM6000 dvb Extension",
 437        .init   = dvb_init,
 438        .fini   = dvb_fini,
 439};
 440
 441static int __init tm6000_dvb_register(void)
 442{
 443        return tm6000_register_extension(&dvb_ops);
 444}
 445
 446static void __exit tm6000_dvb_unregister(void)
 447{
 448        tm6000_unregister_extension(&dvb_ops);
 449}
 450
 451module_init(tm6000_dvb_register);
 452module_exit(tm6000_dvb_unregister);
 453
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.