linux/drivers/media/usb/dvb-usb/gp8psk.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/* DVB USB compliant Linux driver for the
   3 *  - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module
   4 *
   5 * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com)
   6 * Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com)
   7 *
   8 * Thanks to GENPIX for the sample code used to implement this module.
   9 *
  10 * This module is based off the vp7045 and vp702x modules
  11 *
  12 * see Documentation/driver-api/media/drivers/dvb-usb.rst for more information
  13 */
  14#include "gp8psk.h"
  15#include "gp8psk-fe.h"
  16
  17/* debug */
  18static char bcm4500_firmware[] = "dvb-usb-gp8psk-02.fw";
  19int dvb_usb_gp8psk_debug;
  20module_param_named(debug,dvb_usb_gp8psk_debug, int, 0644);
  21MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
  22
  23DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
  24
  25struct gp8psk_state {
  26        unsigned char data[80];
  27};
  28
  29static int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value,
  30                            u16 index, u8 *b, int blen)
  31{
  32        struct gp8psk_state *st = d->priv;
  33        int ret = 0,try = 0;
  34
  35        if (blen > sizeof(st->data))
  36                return -EIO;
  37
  38        if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
  39                return ret;
  40
  41        while (ret >= 0 && ret != blen && try < 3) {
  42                ret = usb_control_msg(d->udev,
  43                        usb_rcvctrlpipe(d->udev,0),
  44                        req,
  45                        USB_TYPE_VENDOR | USB_DIR_IN,
  46                        value, index, st->data, blen,
  47                        2000);
  48                deb_info("reading number %d (ret: %d)\n",try,ret);
  49                try++;
  50        }
  51
  52        if (ret < 0 || ret != blen) {
  53                warn("usb in %d operation failed.", req);
  54                ret = -EIO;
  55        } else {
  56                ret = 0;
  57                memcpy(b, st->data, blen);
  58        }
  59
  60        deb_xfer("in: req. %x, val: %x, ind: %x, buffer: ",req,value,index);
  61        debug_dump(b,blen,deb_xfer);
  62
  63        mutex_unlock(&d->usb_mutex);
  64
  65        return ret;
  66}
  67
  68static int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
  69                             u16 index, u8 *b, int blen)
  70{
  71        struct gp8psk_state *st = d->priv;
  72        int ret;
  73
  74        deb_xfer("out: req. %x, val: %x, ind: %x, buffer: ",req,value,index);
  75        debug_dump(b,blen,deb_xfer);
  76
  77        if (blen > sizeof(st->data))
  78                return -EIO;
  79
  80        if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
  81                return ret;
  82
  83        memcpy(st->data, b, blen);
  84        if (usb_control_msg(d->udev,
  85                        usb_sndctrlpipe(d->udev,0),
  86                        req,
  87                        USB_TYPE_VENDOR | USB_DIR_OUT,
  88                        value, index, st->data, blen,
  89                        2000) != blen) {
  90                warn("usb out operation failed.");
  91                ret = -EIO;
  92        } else
  93                ret = 0;
  94        mutex_unlock(&d->usb_mutex);
  95
  96        return ret;
  97}
  98
  99
 100static int gp8psk_get_fw_version(struct dvb_usb_device *d, u8 *fw_vers)
 101{
 102        return gp8psk_usb_in_op(d, GET_FW_VERS, 0, 0, fw_vers, 6);
 103}
 104
 105static int gp8psk_get_fpga_version(struct dvb_usb_device *d, u8 *fpga_vers)
 106{
 107        return gp8psk_usb_in_op(d, GET_FPGA_VERS, 0, 0, fpga_vers, 1);
 108}
 109
 110static void gp8psk_info(struct dvb_usb_device *d)
 111{
 112        u8 fpga_vers, fw_vers[6];
 113
 114        if (!gp8psk_get_fw_version(d, fw_vers))
 115                info("FW Version = %i.%02i.%i (0x%x)  Build %4i/%02i/%02i",
 116                fw_vers[2], fw_vers[1], fw_vers[0], GP8PSK_FW_VERS(fw_vers),
 117                2000 + fw_vers[5], fw_vers[4], fw_vers[3]);
 118        else
 119                info("failed to get FW version");
 120
 121        if (!gp8psk_get_fpga_version(d, &fpga_vers))
 122                info("FPGA Version = %i", fpga_vers);
 123        else
 124                info("failed to get FPGA version");
 125}
 126
 127static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d)
 128{
 129        int ret;
 130        const struct firmware *fw = NULL;
 131        const u8 *ptr;
 132        u8 *buf;
 133        if ((ret = request_firmware(&fw, bcm4500_firmware,
 134                                        &d->udev->dev)) != 0) {
 135                err("did not find the bcm4500 firmware file '%s' (status %d). You can use <kernel_dir>/scripts/get_dvb_firmware to get the firmware",
 136                        bcm4500_firmware,ret);
 137                return ret;
 138        }
 139
 140        ret = -EINVAL;
 141
 142        if (gp8psk_usb_out_op(d, LOAD_BCM4500,1,0,NULL, 0))
 143                goto out_rel_fw;
 144
 145        info("downloading bcm4500 firmware from file '%s'",bcm4500_firmware);
 146
 147        ptr = fw->data;
 148        buf = kmalloc(64, GFP_KERNEL);
 149        if (!buf) {
 150                ret = -ENOMEM;
 151                goto out_rel_fw;
 152        }
 153
 154        while (ptr[0] != 0xff) {
 155                u16 buflen = ptr[0] + 4;
 156                if (ptr + buflen >= fw->data + fw->size) {
 157                        err("failed to load bcm4500 firmware.");
 158                        goto out_free;
 159                }
 160                if (buflen > 64) {
 161                        err("firmware chunk size bigger than 64 bytes.");
 162                        goto out_free;
 163                }
 164
 165                memcpy(buf, ptr, buflen);
 166                if (dvb_usb_generic_write(d, buf, buflen)) {
 167                        err("failed to load bcm4500 firmware.");
 168                        goto out_free;
 169                }
 170                ptr += buflen;
 171        }
 172
 173        ret = 0;
 174
 175out_free:
 176        kfree(buf);
 177out_rel_fw:
 178        release_firmware(fw);
 179
 180        return ret;
 181}
 182
 183static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
 184{
 185        u8 status, buf;
 186        int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct);
 187
 188        if (onoff) {
 189                gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1);
 190                if (! (status & bm8pskStarted)) {  /* started */
 191                        if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K)
 192                                gp8psk_usb_out_op(d, CW3K_INIT, 1, 0, NULL, 0);
 193                        if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1))
 194                                return -EINVAL;
 195                        gp8psk_info(d);
 196                }
 197
 198                if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
 199                        if (! (status & bm8pskFW_Loaded)) /* BCM4500 firmware loaded */
 200                                if(gp8psk_load_bcm4500fw(d))
 201                                        return -EINVAL;
 202
 203                if (! (status & bmIntersilOn)) /* LNB Power */
 204                        if (gp8psk_usb_in_op(d, START_INTERSIL, 1, 0,
 205                                        &buf, 1))
 206                                return -EINVAL;
 207
 208                /* Set DVB mode to 1 */
 209                if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
 210                        if (gp8psk_usb_out_op(d, SET_DVB_MODE, 1, 0, NULL, 0))
 211                                return -EINVAL;
 212                /* Abort possible TS (if previous tune crashed) */
 213                if (gp8psk_usb_out_op(d, ARM_TRANSFER, 0, 0, NULL, 0))
 214                        return -EINVAL;
 215        } else {
 216                /* Turn off LNB power */
 217                if (gp8psk_usb_in_op(d, START_INTERSIL, 0, 0, &buf, 1))
 218                        return -EINVAL;
 219                /* Turn off 8psk power */
 220                if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))
 221                        return -EINVAL;
 222                if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K)
 223                        gp8psk_usb_out_op(d, CW3K_INIT, 0, 0, NULL, 0);
 224        }
 225        return 0;
 226}
 227
 228static int gp8psk_bcm4500_reload(struct dvb_usb_device *d)
 229{
 230        u8 buf;
 231        int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct);
 232
 233        deb_xfer("reloading firmware\n");
 234
 235        /* Turn off 8psk power */
 236        if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))
 237                return -EINVAL;
 238        /* Turn On 8psk power */
 239        if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1))
 240                return -EINVAL;
 241        /* load BCM4500 firmware */
 242        if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
 243                if (gp8psk_load_bcm4500fw(d))
 244                        return -EINVAL;
 245        return 0;
 246}
 247
 248static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 249{
 250        return gp8psk_usb_out_op(adap->dev, ARM_TRANSFER, onoff, 0 , NULL, 0);
 251}
 252
 253/* Callbacks for gp8psk-fe.c */
 254
 255static int gp8psk_fe_in(void *priv, u8 req, u16 value,
 256                            u16 index, u8 *b, int blen)
 257{
 258        struct dvb_usb_device *d = priv;
 259
 260        return gp8psk_usb_in_op(d, req, value, index, b, blen);
 261}
 262
 263static int gp8psk_fe_out(void *priv, u8 req, u16 value,
 264                            u16 index, u8 *b, int blen)
 265{
 266        struct dvb_usb_device *d = priv;
 267
 268        return gp8psk_usb_out_op(d, req, value, index, b, blen);
 269}
 270
 271static int gp8psk_fe_reload(void *priv)
 272{
 273        struct dvb_usb_device *d = priv;
 274
 275        return gp8psk_bcm4500_reload(d);
 276}
 277
 278static const struct gp8psk_fe_ops gp8psk_fe_ops = {
 279        .in = gp8psk_fe_in,
 280        .out = gp8psk_fe_out,
 281        .reload = gp8psk_fe_reload,
 282};
 283
 284static int gp8psk_frontend_attach(struct dvb_usb_adapter *adap)
 285{
 286        struct dvb_usb_device *d = adap->dev;
 287        int id = le16_to_cpu(d->udev->descriptor.idProduct);
 288        int is_rev1;
 289
 290        is_rev1 = (id == USB_PID_GENPIX_8PSK_REV_1_WARM) ? true : false;
 291
 292        adap->fe_adap[0].fe = dvb_attach(gp8psk_fe_attach,
 293                                         &gp8psk_fe_ops, d, is_rev1);
 294        return 0;
 295}
 296
 297static struct dvb_usb_device_properties gp8psk_properties;
 298
 299static int gp8psk_usb_probe(struct usb_interface *intf,
 300                const struct usb_device_id *id)
 301{
 302        int ret;
 303        struct usb_device *udev = interface_to_usbdev(intf);
 304        ret = dvb_usb_device_init(intf, &gp8psk_properties,
 305                                  THIS_MODULE, NULL, adapter_nr);
 306        if (ret == 0) {
 307                info("found Genpix USB device pID = %x (hex)",
 308                        le16_to_cpu(udev->descriptor.idProduct));
 309        }
 310        return ret;
 311}
 312
 313static struct usb_device_id gp8psk_usb_table [] = {
 314            { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_COLD) },
 315            { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_WARM) },
 316            { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_2) },
 317            { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_1) },
 318            { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_2) },
 319/*          { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) }, */
 320            { 0 },
 321};
 322MODULE_DEVICE_TABLE(usb, gp8psk_usb_table);
 323
 324static struct dvb_usb_device_properties gp8psk_properties = {
 325        .usb_ctrl = CYPRESS_FX2,
 326        .firmware = "dvb-usb-gp8psk-01.fw",
 327
 328        .size_of_priv = sizeof(struct gp8psk_state),
 329
 330        .num_adapters = 1,
 331        .adapter = {
 332                {
 333                .num_frontends = 1,
 334                .fe = {{
 335                        .streaming_ctrl   = gp8psk_streaming_ctrl,
 336                        .frontend_attach  = gp8psk_frontend_attach,
 337                        /* parameter for the MPEG2-data transfer */
 338                        .stream = {
 339                                .type = USB_BULK,
 340                                .count = 7,
 341                                .endpoint = 0x82,
 342                                .u = {
 343                                        .bulk = {
 344                                                .buffersize = 8192,
 345                                        }
 346                                }
 347                        },
 348                }},
 349                }
 350        },
 351        .power_ctrl       = gp8psk_power_ctrl,
 352
 353        .generic_bulk_ctrl_endpoint = 0x01,
 354
 355        .num_device_descs = 4,
 356        .devices = {
 357                { .name = "Genpix 8PSK-to-USB2 Rev.1 DVB-S receiver",
 358                  .cold_ids = { &gp8psk_usb_table[0], NULL },
 359                  .warm_ids = { &gp8psk_usb_table[1], NULL },
 360                },
 361                { .name = "Genpix 8PSK-to-USB2 Rev.2 DVB-S receiver",
 362                  .cold_ids = { NULL },
 363                  .warm_ids = { &gp8psk_usb_table[2], NULL },
 364                },
 365                { .name = "Genpix SkyWalker-1 DVB-S receiver",
 366                  .cold_ids = { NULL },
 367                  .warm_ids = { &gp8psk_usb_table[3], NULL },
 368                },
 369                { .name = "Genpix SkyWalker-2 DVB-S receiver",
 370                  .cold_ids = { NULL },
 371                  .warm_ids = { &gp8psk_usb_table[4], NULL },
 372                },
 373                { NULL },
 374        }
 375};
 376
 377/* usb specific object needed to register this driver with the usb subsystem */
 378static struct usb_driver gp8psk_usb_driver = {
 379        .name           = "dvb_usb_gp8psk",
 380        .probe          = gp8psk_usb_probe,
 381        .disconnect = dvb_usb_device_exit,
 382        .id_table       = gp8psk_usb_table,
 383};
 384
 385module_usb_driver(gp8psk_usb_driver);
 386
 387MODULE_AUTHOR("Alan Nisota <alannisota@gamil.com>");
 388MODULE_DESCRIPTION("Driver for Genpix DVB-S");
 389MODULE_VERSION("1.1");
 390MODULE_LICENSE("GPL");
 391