linux/drivers/media/dvb/dvb-usb/gl861.c
<<
>>
Prefs
   1/* DVB USB compliant linux driver for GL861 USB2.0 devices.
   2 *
   3 *      This program is free software; you can redistribute it and/or modify it
   4 *      under the terms of the GNU General Public License as published by the
   5 *      Free Software Foundation, version 2.
   6 *
   7 * see Documentation/dvb/README.dvb-usb for more information
   8 */
   9#include "gl861.h"
  10
  11#include "zl10353.h"
  12#include "qt1010.h"
  13
  14/* debug */
  15static int dvb_usb_gl861_debug;
  16module_param_named(debug, dvb_usb_gl861_debug, int, 0644);
  17MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))."
  18        DVB_USB_DEBUG_STATUS);
  19DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
  20
  21static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr,
  22                         u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
  23{
  24        u16 index;
  25        u16 value = addr << (8 + 1);
  26        int wo = (rbuf == NULL || rlen == 0); /* write-only */
  27        u8 req, type;
  28
  29        if (wo) {
  30                req = GL861_REQ_I2C_WRITE;
  31                type = GL861_WRITE;
  32        } else { /* rw */
  33                req = GL861_REQ_I2C_READ;
  34                type = GL861_READ;
  35        }
  36
  37        switch (wlen) {
  38        case 1:
  39                index = wbuf[0];
  40                break;
  41        case 2:
  42                index = wbuf[0];
  43                value = value + wbuf[1];
  44                break;
  45        default:
  46                warn("wlen = %x, aborting.", wlen);
  47                return -EINVAL;
  48        }
  49
  50        msleep(1); /* avoid I2C errors */
  51
  52        return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), req, type,
  53                               value, index, rbuf, rlen, 2000);
  54}
  55
  56/* I2C */
  57static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
  58                          int num)
  59{
  60        struct dvb_usb_device *d = i2c_get_adapdata(adap);
  61        int i;
  62
  63        if (num > 2)
  64                return -EINVAL;
  65
  66        if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
  67                return -EAGAIN;
  68
  69        for (i = 0; i < num; i++) {
  70                /* write/read request */
  71                if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
  72                        if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf,
  73                                msg[i].len, msg[i+1].buf, msg[i+1].len) < 0)
  74                                break;
  75                        i++;
  76                } else
  77                        if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf,
  78                                          msg[i].len, NULL, 0) < 0)
  79                                break;
  80        }
  81
  82        mutex_unlock(&d->i2c_mutex);
  83        return i;
  84}
  85
  86static u32 gl861_i2c_func(struct i2c_adapter *adapter)
  87{
  88        return I2C_FUNC_I2C;
  89}
  90
  91static struct i2c_algorithm gl861_i2c_algo = {
  92        .master_xfer   = gl861_i2c_xfer,
  93        .functionality = gl861_i2c_func,
  94};
  95
  96/* Callbacks for DVB USB */
  97static struct zl10353_config gl861_zl10353_config = {
  98        .demod_address = 0x0f,
  99        .no_tuner = 1,
 100        .parallel_ts = 1,
 101};
 102
 103static int gl861_frontend_attach(struct dvb_usb_adapter *adap)
 104{
 105
 106        adap->fe = dvb_attach(zl10353_attach, &gl861_zl10353_config,
 107                &adap->dev->i2c_adap);
 108        if (adap->fe == NULL)
 109                return -EIO;
 110
 111        return 0;
 112}
 113
 114static struct qt1010_config gl861_qt1010_config = {
 115        .i2c_address = 0x62
 116};
 117
 118static int gl861_tuner_attach(struct dvb_usb_adapter *adap)
 119{
 120        return dvb_attach(qt1010_attach,
 121                          adap->fe, &adap->dev->i2c_adap,
 122                          &gl861_qt1010_config) == NULL ? -ENODEV : 0;
 123}
 124
 125/* DVB USB Driver stuff */
 126static struct dvb_usb_device_properties gl861_properties;
 127
 128static int gl861_probe(struct usb_interface *intf,
 129                       const struct usb_device_id *id)
 130{
 131        struct dvb_usb_device *d;
 132        struct usb_host_interface *alt;
 133        int ret;
 134
 135        if (intf->num_altsetting < 2)
 136                return -ENODEV;
 137
 138        ret = dvb_usb_device_init(intf, &gl861_properties, THIS_MODULE, &d,
 139                                  adapter_nr);
 140        if (ret == 0) {
 141                alt = usb_altnum_to_altsetting(intf, 0);
 142
 143                if (alt == NULL) {
 144                        deb_rc("not alt found!\n");
 145                        return -ENODEV;
 146                }
 147
 148                ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
 149                                        alt->desc.bAlternateSetting);
 150        }
 151
 152        return ret;
 153}
 154
 155static struct usb_device_id gl861_table [] = {
 156                { USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580_55801) },
 157                { USB_DEVICE(USB_VID_ALINK, USB_VID_ALINK_DTU) },
 158                { }             /* Terminating entry */
 159};
 160MODULE_DEVICE_TABLE(usb, gl861_table);
 161
 162static struct dvb_usb_device_properties gl861_properties = {
 163        .caps = DVB_USB_IS_AN_I2C_ADAPTER,
 164        .usb_ctrl = DEVICE_SPECIFIC,
 165
 166        .size_of_priv     = 0,
 167
 168        .num_adapters = 1,
 169        .adapter = {{
 170
 171                .frontend_attach  = gl861_frontend_attach,
 172                .tuner_attach     = gl861_tuner_attach,
 173
 174                .stream = {
 175                        .type = USB_BULK,
 176                        .count = 7,
 177                        .endpoint = 0x81,
 178                        .u = {
 179                                .bulk = {
 180                                        .buffersize = 512,
 181                                }
 182                        }
 183                },
 184        } },
 185        .i2c_algo         = &gl861_i2c_algo,
 186
 187        .num_device_descs = 2,
 188        .devices = {
 189                {
 190                        .name = "MSI Mega Sky 55801 DVB-T USB2.0",
 191                        .cold_ids = { NULL },
 192                        .warm_ids = { &gl861_table[0], NULL },
 193                },
 194                {
 195                        .name = "A-LINK DTU DVB-T USB2.0",
 196                        .cold_ids = { NULL },
 197                        .warm_ids = { &gl861_table[1], NULL },
 198                },
 199        }
 200};
 201
 202static struct usb_driver gl861_driver = {
 203        .name           = "dvb_usb_gl861",
 204        .probe          = gl861_probe,
 205        .disconnect     = dvb_usb_device_exit,
 206        .id_table       = gl861_table,
 207};
 208
 209/* module stuff */
 210static int __init gl861_module_init(void)
 211{
 212        int ret;
 213
 214        ret = usb_register(&gl861_driver);
 215        if (ret)
 216                err("usb_register failed. Error number %d", ret);
 217
 218        return ret;
 219}
 220
 221static void __exit gl861_module_exit(void)
 222{
 223        /* deregister this driver from the USB subsystem */
 224        usb_deregister(&gl861_driver);
 225}
 226
 227module_init(gl861_module_init);
 228module_exit(gl861_module_exit);
 229
 230MODULE_AUTHOR("Carl Lundqvist <comabug@gmail.com>");
 231MODULE_DESCRIPTION("Driver MSI Mega Sky 580 DVB-T USB2.0 / GL861");
 232MODULE_VERSION("0.1");
 233MODULE_LICENSE("GPL");
 234
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.