linux/drivers/media/usb/dvb-usb/dtt200u.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/* DVB USB library compliant Linux driver for the WideView/ Yakumo/ Hama/
   3 * Typhoon/ Yuan/ Miglia DVB-T USB2.0 receiver.
   4 *
   5 * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@posteo.de)
   6 *
   7 * Thanks to Steve Chang from WideView for providing support for the WT-220U.
   8 *
   9 * see Documentation/driver-api/media/drivers/dvb-usb.rst for more information
  10 */
  11#include "dtt200u.h"
  12
  13/* debug */
  14int dvb_usb_dtt200u_debug;
  15module_param_named(debug,dvb_usb_dtt200u_debug, int, 0644);
  16MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2 (or-able))." DVB_USB_DEBUG_STATUS);
  17
  18DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
  19
  20struct dtt200u_state {
  21        unsigned char data[80];
  22};
  23
  24static int dtt200u_power_ctrl(struct dvb_usb_device *d, int onoff)
  25{
  26        struct dtt200u_state *st = d->priv;
  27        int ret = 0;
  28
  29        mutex_lock(&d->data_mutex);
  30
  31        st->data[0] = SET_INIT;
  32
  33        if (onoff)
  34                ret = dvb_usb_generic_write(d, st->data, 2);
  35
  36        mutex_unlock(&d->data_mutex);
  37        return ret;
  38}
  39
  40static int dtt200u_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
  41{
  42        struct dvb_usb_device *d = adap->dev;
  43        struct dtt200u_state *st = d->priv;
  44        int ret;
  45
  46        mutex_lock(&d->data_mutex);
  47        st->data[0] = SET_STREAMING;
  48        st->data[1] = onoff;
  49
  50        ret = dvb_usb_generic_write(adap->dev, st->data, 2);
  51        if (ret < 0)
  52                goto ret;
  53
  54        if (onoff)
  55                goto ret;
  56
  57        st->data[0] = RESET_PID_FILTER;
  58        ret = dvb_usb_generic_write(adap->dev, st->data, 1);
  59
  60ret:
  61        mutex_unlock(&d->data_mutex);
  62
  63        return ret;
  64}
  65
  66static int dtt200u_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff)
  67{
  68        struct dvb_usb_device *d = adap->dev;
  69        struct dtt200u_state *st = d->priv;
  70        int ret;
  71
  72        pid = onoff ? pid : 0;
  73
  74        mutex_lock(&d->data_mutex);
  75        st->data[0] = SET_PID_FILTER;
  76        st->data[1] = index;
  77        st->data[2] = pid & 0xff;
  78        st->data[3] = (pid >> 8) & 0x1f;
  79
  80        ret = dvb_usb_generic_write(adap->dev, st->data, 4);
  81        mutex_unlock(&d->data_mutex);
  82
  83        return ret;
  84}
  85
  86static int dtt200u_rc_query(struct dvb_usb_device *d)
  87{
  88        struct dtt200u_state *st = d->priv;
  89        u32 scancode;
  90        int ret;
  91
  92        mutex_lock(&d->data_mutex);
  93        st->data[0] = GET_RC_CODE;
  94
  95        ret = dvb_usb_generic_rw(d, st->data, 1, st->data, 5, 0);
  96        if (ret < 0)
  97                goto ret;
  98
  99        if (st->data[0] == 1) {
 100                enum rc_proto proto = RC_PROTO_NEC;
 101
 102                scancode = st->data[1];
 103                if ((u8) ~st->data[1] != st->data[2]) {
 104                        /* Extended NEC */
 105                        scancode = scancode << 8;
 106                        scancode |= st->data[2];
 107                        proto = RC_PROTO_NECX;
 108                }
 109                scancode = scancode << 8;
 110                scancode |= st->data[3];
 111
 112                /* Check command checksum is ok */
 113                if ((u8) ~st->data[3] == st->data[4])
 114                        rc_keydown(d->rc_dev, proto, scancode, 0);
 115                else
 116                        rc_keyup(d->rc_dev);
 117        } else if (st->data[0] == 2) {
 118                rc_repeat(d->rc_dev);
 119        } else {
 120                rc_keyup(d->rc_dev);
 121        }
 122
 123        if (st->data[0] != 0)
 124                deb_info("st->data: %*ph\n", 5, st->data);
 125
 126ret:
 127        mutex_unlock(&d->data_mutex);
 128        return ret;
 129}
 130
 131static int dtt200u_frontend_attach(struct dvb_usb_adapter *adap)
 132{
 133        adap->fe_adap[0].fe = dtt200u_fe_attach(adap->dev);
 134        return 0;
 135}
 136
 137static struct dvb_usb_device_properties dtt200u_properties;
 138static struct dvb_usb_device_properties wt220u_fc_properties;
 139static struct dvb_usb_device_properties wt220u_properties;
 140static struct dvb_usb_device_properties wt220u_zl0353_properties;
 141static struct dvb_usb_device_properties wt220u_miglia_properties;
 142
 143static int dtt200u_usb_probe(struct usb_interface *intf,
 144                const struct usb_device_id *id)
 145{
 146        if (0 == dvb_usb_device_init(intf, &dtt200u_properties,
 147                                     THIS_MODULE, NULL, adapter_nr) ||
 148            0 == dvb_usb_device_init(intf, &wt220u_properties,
 149                                     THIS_MODULE, NULL, adapter_nr) ||
 150            0 == dvb_usb_device_init(intf, &wt220u_fc_properties,
 151                                     THIS_MODULE, NULL, adapter_nr) ||
 152            0 == dvb_usb_device_init(intf, &wt220u_zl0353_properties,
 153                                     THIS_MODULE, NULL, adapter_nr) ||
 154            0 == dvb_usb_device_init(intf, &wt220u_miglia_properties,
 155                                     THIS_MODULE, NULL, adapter_nr))
 156                return 0;
 157
 158        return -ENODEV;
 159}
 160
 161static struct usb_device_id dtt200u_usb_table [] = {
 162        { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_COLD) },
 163        { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_WARM) },
 164        { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_COLD)  },
 165        { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_WARM)  },
 166        { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_COLD)  },
 167        { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_WARM)  },
 168        { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_COLD)  },
 169        { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_WARM)  },
 170        { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZAP250_COLD)  },
 171        { USB_DEVICE(USB_VID_MIGLIA, USB_PID_WT220U_ZAP250_COLD)  },
 172        { 0 },
 173};
 174MODULE_DEVICE_TABLE(usb, dtt200u_usb_table);
 175
 176static struct dvb_usb_device_properties dtt200u_properties = {
 177        .usb_ctrl = CYPRESS_FX2,
 178        .firmware = "dvb-usb-dtt200u-01.fw",
 179
 180        .size_of_priv     = sizeof(struct dtt200u_state),
 181
 182        .num_adapters = 1,
 183        .adapter = {
 184                {
 185                .num_frontends = 1,
 186                .fe = {{
 187                        .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
 188                        .pid_filter_count = 15,
 189
 190        .streaming_ctrl  = dtt200u_streaming_ctrl,
 191        .pid_filter      = dtt200u_pid_filter,
 192        .frontend_attach = dtt200u_frontend_attach,
 193        /* parameter for the MPEG2-data transfer */
 194                        .stream = {
 195                                .type = USB_BULK,
 196                .count = 7,
 197                .endpoint = 0x02,
 198                .u = {
 199                        .bulk = {
 200                                .buffersize = 4096,
 201                        }
 202                }
 203        },
 204                }},
 205                }
 206        },
 207        .power_ctrl      = dtt200u_power_ctrl,
 208
 209        .rc.core = {
 210                .rc_interval     = 300,
 211                .rc_codes        = RC_MAP_DTT200U,
 212                .rc_query        = dtt200u_rc_query,
 213                .allowed_protos  = RC_PROTO_BIT_NEC,
 214        },
 215
 216        .generic_bulk_ctrl_endpoint = 0x01,
 217
 218        .num_device_descs = 1,
 219        .devices = {
 220                { .name = "WideView/Yuan/Yakumo/Hama/Typhoon DVB-T USB2.0 (WT-200U)",
 221                  .cold_ids = { &dtt200u_usb_table[0], NULL },
 222                  .warm_ids = { &dtt200u_usb_table[1], NULL },
 223                },
 224                { NULL },
 225        }
 226};
 227
 228static struct dvb_usb_device_properties wt220u_properties = {
 229        .usb_ctrl = CYPRESS_FX2,
 230        .firmware = "dvb-usb-wt220u-02.fw",
 231
 232        .size_of_priv     = sizeof(struct dtt200u_state),
 233
 234        .num_adapters = 1,
 235        .adapter = {
 236                {
 237                .num_frontends = 1,
 238                .fe = {{
 239                        .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
 240                        .pid_filter_count = 15,
 241
 242        .streaming_ctrl  = dtt200u_streaming_ctrl,
 243        .pid_filter      = dtt200u_pid_filter,
 244        .frontend_attach = dtt200u_frontend_attach,
 245        /* parameter for the MPEG2-data transfer */
 246                        .stream = {
 247                                .type = USB_BULK,
 248                .count = 7,
 249                .endpoint = 0x02,
 250                .u = {
 251                        .bulk = {
 252                                .buffersize = 4096,
 253                        }
 254                }
 255        },
 256                }},
 257                }
 258        },
 259        .power_ctrl      = dtt200u_power_ctrl,
 260
 261        .rc.core = {
 262                .rc_interval     = 300,
 263                .rc_codes        = RC_MAP_DTT200U,
 264                .rc_query        = dtt200u_rc_query,
 265                .allowed_protos  = RC_PROTO_BIT_NEC,
 266        },
 267
 268        .generic_bulk_ctrl_endpoint = 0x01,
 269
 270        .num_device_descs = 1,
 271        .devices = {
 272                { .name = "WideView WT-220U PenType Receiver (Typhoon/Freecom)",
 273                  .cold_ids = { &dtt200u_usb_table[2], &dtt200u_usb_table[8], NULL },
 274                  .warm_ids = { &dtt200u_usb_table[3], NULL },
 275                },
 276                { NULL },
 277        }
 278};
 279
 280static struct dvb_usb_device_properties wt220u_fc_properties = {
 281        .usb_ctrl = CYPRESS_FX2,
 282        .firmware = "dvb-usb-wt220u-fc03.fw",
 283
 284        .size_of_priv     = sizeof(struct dtt200u_state),
 285
 286        .num_adapters = 1,
 287        .adapter = {
 288                {
 289                .num_frontends = 1,
 290                .fe = {{
 291                        .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
 292                        .pid_filter_count = 15,
 293
 294        .streaming_ctrl  = dtt200u_streaming_ctrl,
 295        .pid_filter      = dtt200u_pid_filter,
 296        .frontend_attach = dtt200u_frontend_attach,
 297        /* parameter for the MPEG2-data transfer */
 298                        .stream = {
 299                                .type = USB_BULK,
 300                .count = 7,
 301                                .endpoint = 0x06,
 302                .u = {
 303                        .bulk = {
 304                                .buffersize = 4096,
 305                        }
 306                }
 307        },
 308                }},
 309                }
 310        },
 311        .power_ctrl      = dtt200u_power_ctrl,
 312
 313        .rc.core = {
 314                .rc_interval     = 300,
 315                .rc_codes        = RC_MAP_DTT200U,
 316                .rc_query        = dtt200u_rc_query,
 317                .allowed_protos  = RC_PROTO_BIT_NEC,
 318        },
 319
 320        .generic_bulk_ctrl_endpoint = 0x01,
 321
 322        .num_device_descs = 1,
 323        .devices = {
 324                { .name = "WideView WT-220U PenType Receiver (Typhoon/Freecom)",
 325                  .cold_ids = { &dtt200u_usb_table[6], NULL },
 326                  .warm_ids = { &dtt200u_usb_table[7], NULL },
 327                },
 328                { NULL },
 329        }
 330};
 331
 332static struct dvb_usb_device_properties wt220u_zl0353_properties = {
 333        .usb_ctrl = CYPRESS_FX2,
 334        .firmware = "dvb-usb-wt220u-zl0353-01.fw",
 335
 336        .size_of_priv     = sizeof(struct dtt200u_state),
 337
 338        .num_adapters = 1,
 339        .adapter = {
 340                {
 341                .num_frontends = 1,
 342                .fe = {{
 343                        .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
 344                        .pid_filter_count = 15,
 345
 346                        .streaming_ctrl  = dtt200u_streaming_ctrl,
 347                        .pid_filter      = dtt200u_pid_filter,
 348                        .frontend_attach = dtt200u_frontend_attach,
 349                        /* parameter for the MPEG2-data transfer */
 350                        .stream = {
 351                                .type = USB_BULK,
 352                                .count = 7,
 353                                .endpoint = 0x02,
 354                                .u = {
 355                                        .bulk = {
 356                                                .buffersize = 4096,
 357                                        }
 358                                }
 359                        },
 360                }},
 361                }
 362        },
 363        .power_ctrl      = dtt200u_power_ctrl,
 364
 365        .rc.core = {
 366                .rc_interval     = 300,
 367                .rc_codes        = RC_MAP_DTT200U,
 368                .rc_query        = dtt200u_rc_query,
 369                .allowed_protos  = RC_PROTO_BIT_NEC,
 370        },
 371
 372        .generic_bulk_ctrl_endpoint = 0x01,
 373
 374        .num_device_descs = 1,
 375        .devices = {
 376                { .name = "WideView WT-220U PenType Receiver (based on ZL353)",
 377                  .cold_ids = { &dtt200u_usb_table[4], NULL },
 378                  .warm_ids = { &dtt200u_usb_table[5], NULL },
 379                },
 380                { NULL },
 381        }
 382};
 383
 384static struct dvb_usb_device_properties wt220u_miglia_properties = {
 385        .usb_ctrl = CYPRESS_FX2,
 386        .firmware = "dvb-usb-wt220u-miglia-01.fw",
 387
 388        .size_of_priv     = sizeof(struct dtt200u_state),
 389
 390        .num_adapters = 1,
 391        .generic_bulk_ctrl_endpoint = 0x01,
 392
 393        .num_device_descs = 1,
 394        .devices = {
 395                { .name = "WideView WT-220U PenType Receiver (Miglia)",
 396                  .cold_ids = { &dtt200u_usb_table[9], NULL },
 397                  /* This device turns into WT220U_ZL0353_WARM when fw
 398                     has been uploaded */
 399                  .warm_ids = { NULL },
 400                },
 401                { NULL },
 402        }
 403};
 404
 405/* usb specific object needed to register this driver with the usb subsystem */
 406static struct usb_driver dtt200u_usb_driver = {
 407        .name           = "dvb_usb_dtt200u",
 408        .probe          = dtt200u_usb_probe,
 409        .disconnect = dvb_usb_device_exit,
 410        .id_table       = dtt200u_usb_table,
 411};
 412
 413module_usb_driver(dtt200u_usb_driver);
 414
 415MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
 416MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon/Club3D/Miglia DVB-T USB2.0 devices");
 417MODULE_VERSION("1.0");
 418MODULE_LICENSE("GPL");
 419