Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  tm6000-dvb.c - dvb-t support for TM5600/TM6000/TM6010 USB video capture devices
0004  *
0005  *  Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
0006  */
0007 
0008 #include <linux/kernel.h>
0009 #include <linux/slab.h>
0010 #include <linux/usb.h>
0011 
0012 #include "tm6000.h"
0013 #include "tm6000-regs.h"
0014 
0015 #include "zl10353.h"
0016 
0017 #include <media/tuner.h>
0018 
0019 #include "xc2028.h"
0020 #include "xc5000.h"
0021 
0022 MODULE_DESCRIPTION("DVB driver extension module for tm5600/6000/6010 based TV cards");
0023 MODULE_AUTHOR("Mauro Carvalho Chehab");
0024 MODULE_LICENSE("GPL");
0025 
0026 static int debug;
0027 
0028 module_param(debug, int, 0644);
0029 MODULE_PARM_DESC(debug, "enable debug message");
0030 
0031 static inline void print_err_status(struct tm6000_core *dev,
0032                     int packet, int status)
0033 {
0034     char *errmsg = "Unknown";
0035 
0036     switch (status) {
0037     case -ENOENT:
0038         errmsg = "unlinked synchronously";
0039         break;
0040     case -ECONNRESET:
0041         errmsg = "unlinked asynchronously";
0042         break;
0043     case -ENOSR:
0044         errmsg = "Buffer error (overrun)";
0045         break;
0046     case -EPIPE:
0047         errmsg = "Stalled (device not responding)";
0048         break;
0049     case -EOVERFLOW:
0050         errmsg = "Babble (bad cable?)";
0051         break;
0052     case -EPROTO:
0053         errmsg = "Bit-stuff error (bad cable?)";
0054         break;
0055     case -EILSEQ:
0056         errmsg = "CRC/Timeout (could be anything)";
0057         break;
0058     case -ETIME:
0059         errmsg = "Device does not respond";
0060         break;
0061     }
0062     if (packet < 0) {
0063         dprintk(dev, 1, "URB status %d [%s].\n",
0064             status, errmsg);
0065     } else {
0066         dprintk(dev, 1, "URB packet %d, status %d [%s].\n",
0067             packet, status, errmsg);
0068     }
0069 }
0070 
0071 static void tm6000_urb_received(struct urb *urb)
0072 {
0073     int ret;
0074     struct tm6000_core *dev = urb->context;
0075 
0076     switch (urb->status) {
0077     case 0:
0078     case -ETIMEDOUT:
0079         break;
0080     case -ENOENT:
0081     case -ECONNRESET:
0082     case -ESHUTDOWN:
0083         return;
0084     default:
0085         print_err_status(dev, 0, urb->status);
0086     }
0087 
0088     if (urb->actual_length > 0)
0089         dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer,
0090                            urb->actual_length);
0091 
0092     if (dev->dvb->streams > 0) {
0093         ret = usb_submit_urb(urb, GFP_ATOMIC);
0094         if (ret < 0) {
0095             printk(KERN_ERR "tm6000:  error %s\n", __func__);
0096             kfree(urb->transfer_buffer);
0097             usb_free_urb(urb);
0098             dev->dvb->bulk_urb = NULL;
0099         }
0100     }
0101 }
0102 
0103 static int tm6000_start_stream(struct tm6000_core *dev)
0104 {
0105     int ret;
0106     unsigned int pipe, size;
0107     struct tm6000_dvb *dvb = dev->dvb;
0108 
0109     printk(KERN_INFO "tm6000: got start stream request %s\n", __func__);
0110 
0111     if (dev->mode != TM6000_MODE_DIGITAL) {
0112         tm6000_init_digital_mode(dev);
0113         dev->mode = TM6000_MODE_DIGITAL;
0114     }
0115 
0116     dvb->bulk_urb = usb_alloc_urb(0, GFP_KERNEL);
0117     if (!dvb->bulk_urb)
0118         return -ENOMEM;
0119 
0120     pipe = usb_rcvbulkpipe(dev->udev, dev->bulk_in.endp->desc.bEndpointAddress
0121                               & USB_ENDPOINT_NUMBER_MASK);
0122 
0123     size = usb_maxpacket(dev->udev, pipe);
0124     size = size * 15; /* 512 x 8 or 12 or 15 */
0125 
0126     dvb->bulk_urb->transfer_buffer = kzalloc(size, GFP_KERNEL);
0127     if (!dvb->bulk_urb->transfer_buffer) {
0128         usb_free_urb(dvb->bulk_urb);
0129         dvb->bulk_urb = NULL;
0130         return -ENOMEM;
0131     }
0132 
0133     usb_fill_bulk_urb(dvb->bulk_urb, dev->udev, pipe,
0134                          dvb->bulk_urb->transfer_buffer,
0135                          size,
0136                          tm6000_urb_received, dev);
0137 
0138     ret = usb_clear_halt(dev->udev, pipe);
0139     if (ret < 0) {
0140         printk(KERN_ERR "tm6000: error %i in %s during pipe reset\n",
0141                             ret, __func__);
0142 
0143         kfree(dvb->bulk_urb->transfer_buffer);
0144         usb_free_urb(dvb->bulk_urb);
0145         dvb->bulk_urb = NULL;
0146         return ret;
0147     } else
0148         printk(KERN_ERR "tm6000: pipe reset\n");
0149 
0150 /*  mutex_lock(&tm6000_driver.open_close_mutex); */
0151     ret = usb_submit_urb(dvb->bulk_urb, GFP_ATOMIC);
0152 
0153 /*  mutex_unlock(&tm6000_driver.open_close_mutex); */
0154     if (ret) {
0155         printk(KERN_ERR "tm6000: submit of urb failed (error=%i)\n",
0156                                     ret);
0157 
0158         kfree(dvb->bulk_urb->transfer_buffer);
0159         usb_free_urb(dvb->bulk_urb);
0160         dvb->bulk_urb = NULL;
0161         return ret;
0162     }
0163 
0164     return 0;
0165 }
0166 
0167 static void tm6000_stop_stream(struct tm6000_core *dev)
0168 {
0169     struct tm6000_dvb *dvb = dev->dvb;
0170 
0171     if (dvb->bulk_urb) {
0172         printk(KERN_INFO "urb killing\n");
0173         usb_kill_urb(dvb->bulk_urb);
0174         printk(KERN_INFO "urb buffer free\n");
0175         kfree(dvb->bulk_urb->transfer_buffer);
0176         usb_free_urb(dvb->bulk_urb);
0177         dvb->bulk_urb = NULL;
0178     }
0179 }
0180 
0181 static int tm6000_start_feed(struct dvb_demux_feed *feed)
0182 {
0183     struct dvb_demux *demux = feed->demux;
0184     struct tm6000_core *dev = demux->priv;
0185     struct tm6000_dvb *dvb = dev->dvb;
0186     printk(KERN_INFO "tm6000: got start feed request %s\n", __func__);
0187 
0188     mutex_lock(&dvb->mutex);
0189     if (dvb->streams == 0) {
0190         dvb->streams = 1;
0191 /*      mutex_init(&tm6000_dev->streming_mutex); */
0192         tm6000_start_stream(dev);
0193     } else
0194         ++(dvb->streams);
0195     mutex_unlock(&dvb->mutex);
0196 
0197     return 0;
0198 }
0199 
0200 static int tm6000_stop_feed(struct dvb_demux_feed *feed)
0201 {
0202     struct dvb_demux *demux = feed->demux;
0203     struct tm6000_core *dev = demux->priv;
0204     struct tm6000_dvb *dvb = dev->dvb;
0205 
0206     printk(KERN_INFO "tm6000: got stop feed request %s\n", __func__);
0207 
0208     mutex_lock(&dvb->mutex);
0209 
0210     printk(KERN_INFO "stream %#x\n", dvb->streams);
0211     --(dvb->streams);
0212     if (dvb->streams == 0) {
0213         printk(KERN_INFO "stop stream\n");
0214         tm6000_stop_stream(dev);
0215 /*      mutex_destroy(&tm6000_dev->streaming_mutex); */
0216     }
0217     mutex_unlock(&dvb->mutex);
0218 /*  mutex_destroy(&tm6000_dev->streaming_mutex); */
0219 
0220     return 0;
0221 }
0222 
0223 static int tm6000_dvb_attach_frontend(struct tm6000_core *dev)
0224 {
0225     struct tm6000_dvb *dvb = dev->dvb;
0226 
0227     if (dev->caps.has_zl10353) {
0228         struct zl10353_config config = {
0229                      .demod_address = dev->demod_addr,
0230                      .no_tuner = 1,
0231                      .parallel_ts = 1,
0232                      .if2 = 45700,
0233                      .disable_i2c_gate_ctrl = 1,
0234                     };
0235 
0236         dvb->frontend = dvb_attach(zl10353_attach, &config,
0237                                &dev->i2c_adap);
0238     } else {
0239         printk(KERN_ERR "tm6000: no frontend defined for the device!\n");
0240         return -1;
0241     }
0242 
0243     return (!dvb->frontend) ? -1 : 0;
0244 }
0245 
0246 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
0247 
0248 static int register_dvb(struct tm6000_core *dev)
0249 {
0250     int ret = -1;
0251     struct tm6000_dvb *dvb = dev->dvb;
0252 
0253     mutex_init(&dvb->mutex);
0254 
0255     dvb->streams = 0;
0256 
0257     /* attach the frontend */
0258     ret = tm6000_dvb_attach_frontend(dev);
0259     if (ret < 0) {
0260         printk(KERN_ERR "tm6000: couldn't attach the frontend!\n");
0261         goto err;
0262     }
0263 
0264     ret = dvb_register_adapter(&dvb->adapter, "Trident TVMaster 6000 DVB-T",
0265                     THIS_MODULE, &dev->udev->dev, adapter_nr);
0266     if (ret < 0) {
0267         pr_err("tm6000: couldn't register the adapter!\n");
0268         goto err;
0269     }
0270 
0271     dvb->adapter.priv = dev;
0272 
0273     if (dvb->frontend) {
0274         switch (dev->tuner_type) {
0275         case TUNER_XC2028: {
0276             struct xc2028_config cfg = {
0277                 .i2c_adap = &dev->i2c_adap,
0278                 .i2c_addr = dev->tuner_addr,
0279             };
0280 
0281             dvb->frontend->callback = tm6000_tuner_callback;
0282             ret = dvb_register_frontend(&dvb->adapter, dvb->frontend);
0283             if (ret < 0) {
0284                 printk(KERN_ERR
0285                     "tm6000: couldn't register frontend\n");
0286                 goto adapter_err;
0287             }
0288 
0289             if (!dvb_attach(xc2028_attach, dvb->frontend, &cfg)) {
0290                 printk(KERN_ERR "tm6000: couldn't register frontend (xc3028)\n");
0291                 ret = -EINVAL;
0292                 goto frontend_err;
0293             }
0294             printk(KERN_INFO "tm6000: XC2028/3028 asked to be attached to frontend!\n");
0295             break;
0296             }
0297         case TUNER_XC5000: {
0298             struct xc5000_config cfg = {
0299                 .i2c_address = dev->tuner_addr,
0300             };
0301 
0302             dvb->frontend->callback = tm6000_xc5000_callback;
0303             ret = dvb_register_frontend(&dvb->adapter, dvb->frontend);
0304             if (ret < 0) {
0305                 printk(KERN_ERR
0306                     "tm6000: couldn't register frontend\n");
0307                 goto adapter_err;
0308             }
0309 
0310             if (!dvb_attach(xc5000_attach, dvb->frontend, &dev->i2c_adap, &cfg)) {
0311                 printk(KERN_ERR "tm6000: couldn't register frontend (xc5000)\n");
0312                 ret = -EINVAL;
0313                 goto frontend_err;
0314             }
0315             printk(KERN_INFO "tm6000: XC5000 asked to be attached to frontend!\n");
0316             break;
0317             }
0318         }
0319     } else
0320         printk(KERN_ERR "tm6000: no frontend found\n");
0321 
0322     dvb->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING
0323                                 | DMX_MEMORY_BASED_FILTERING;
0324     dvb->demux.priv = dev;
0325     dvb->demux.filternum = 8;
0326     dvb->demux.feednum = 8;
0327     dvb->demux.start_feed = tm6000_start_feed;
0328     dvb->demux.stop_feed = tm6000_stop_feed;
0329     dvb->demux.write_to_decoder = NULL;
0330     ret = dvb_dmx_init(&dvb->demux);
0331     if (ret < 0) {
0332         printk(KERN_ERR "tm6000: dvb_dmx_init failed (errno = %d)\n", ret);
0333         goto frontend_err;
0334     }
0335 
0336     dvb->dmxdev.filternum = dev->dvb->demux.filternum;
0337     dvb->dmxdev.demux = &dev->dvb->demux.dmx;
0338     dvb->dmxdev.capabilities = 0;
0339 
0340     ret =  dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
0341     if (ret < 0) {
0342         printk(KERN_ERR "tm6000: dvb_dmxdev_init failed (errno = %d)\n", ret);
0343         goto dvb_dmx_err;
0344     }
0345 
0346     return 0;
0347 
0348 dvb_dmx_err:
0349     dvb_dmx_release(&dvb->demux);
0350 frontend_err:
0351     if (dvb->frontend) {
0352         dvb_unregister_frontend(dvb->frontend);
0353         dvb_frontend_detach(dvb->frontend);
0354     }
0355 adapter_err:
0356     dvb_unregister_adapter(&dvb->adapter);
0357 err:
0358     return ret;
0359 }
0360 
0361 static void unregister_dvb(struct tm6000_core *dev)
0362 {
0363     struct tm6000_dvb *dvb = dev->dvb;
0364 
0365     if (dvb->bulk_urb) {
0366         struct urb *bulk_urb = dvb->bulk_urb;
0367 
0368         kfree(bulk_urb->transfer_buffer);
0369         bulk_urb->transfer_buffer = NULL;
0370         usb_unlink_urb(bulk_urb);
0371         usb_free_urb(bulk_urb);
0372     }
0373 
0374 /*  mutex_lock(&tm6000_driver.open_close_mutex); */
0375     if (dvb->frontend) {
0376         dvb_unregister_frontend(dvb->frontend);
0377         dvb_frontend_detach(dvb->frontend);
0378     }
0379 
0380     dvb_dmxdev_release(&dvb->dmxdev);
0381     dvb_dmx_release(&dvb->demux);
0382     dvb_unregister_adapter(&dvb->adapter);
0383     mutex_destroy(&dvb->mutex);
0384 /*  mutex_unlock(&tm6000_driver.open_close_mutex); */
0385 }
0386 
0387 static int dvb_init(struct tm6000_core *dev)
0388 {
0389     struct tm6000_dvb *dvb;
0390     int rc;
0391 
0392     if (!dev)
0393         return 0;
0394 
0395     if (!dev->caps.has_dvb)
0396         return 0;
0397 
0398     if (dev->udev->speed == USB_SPEED_FULL) {
0399         printk(KERN_INFO "This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)\n");
0400         return 0;
0401     }
0402 
0403     dvb = kzalloc(sizeof(struct tm6000_dvb), GFP_KERNEL);
0404     if (!dvb)
0405         return -ENOMEM;
0406 
0407     dev->dvb = dvb;
0408 
0409     rc = register_dvb(dev);
0410     if (rc < 0) {
0411         kfree(dvb);
0412         dev->dvb = NULL;
0413         return 0;
0414     }
0415 
0416     return 0;
0417 }
0418 
0419 static int dvb_fini(struct tm6000_core *dev)
0420 {
0421     if (!dev)
0422         return 0;
0423 
0424     if (!dev->caps.has_dvb)
0425         return 0;
0426 
0427     if (dev->dvb) {
0428         unregister_dvb(dev);
0429         kfree(dev->dvb);
0430         dev->dvb = NULL;
0431     }
0432 
0433     return 0;
0434 }
0435 
0436 static struct tm6000_ops dvb_ops = {
0437     .type   = TM6000_DVB,
0438     .name   = "TM6000 dvb Extension",
0439     .init   = dvb_init,
0440     .fini   = dvb_fini,
0441 };
0442 
0443 static int __init tm6000_dvb_register(void)
0444 {
0445     return tm6000_register_extension(&dvb_ops);
0446 }
0447 
0448 static void __exit tm6000_dvb_unregister(void)
0449 {
0450     tm6000_unregister_extension(&dvb_ops);
0451 }
0452 
0453 module_init(tm6000_dvb_register);
0454 module_exit(tm6000_dvb_unregister);