18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* DVB USB compliant linux driver for Nebula Electronics uDigiTV DVB-T USB2.0 38c2ecf20Sopenharmony_ci * receiver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@posteo.de) 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * partly based on the SDK published by Nebula Electronics 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * see Documentation/driver-api/media/drivers/dvb-usb.rst for more information 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci#include "digitv.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "mt352.h" 148c2ecf20Sopenharmony_ci#include "nxt6000.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci/* debug */ 178c2ecf20Sopenharmony_cistatic int dvb_usb_digitv_debug; 188c2ecf20Sopenharmony_cimodule_param_named(debug,dvb_usb_digitv_debug, int, 0644); 198c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ciDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define deb_rc(args...) dprintk(dvb_usb_digitv_debug,0x01,args) 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic int digitv_ctrl_msg(struct dvb_usb_device *d, 268c2ecf20Sopenharmony_ci u8 cmd, u8 vv, u8 *wbuf, int wlen, u8 *rbuf, int rlen) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci struct digitv_state *st = d->priv; 298c2ecf20Sopenharmony_ci int ret, wo; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci wo = (rbuf == NULL || rlen == 0); /* write-only */ 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci if (wlen > 4 || rlen > 4) 348c2ecf20Sopenharmony_ci return -EIO; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci memset(st->sndbuf, 0, 7); 378c2ecf20Sopenharmony_ci memset(st->rcvbuf, 0, 7); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci st->sndbuf[0] = cmd; 408c2ecf20Sopenharmony_ci st->sndbuf[1] = vv; 418c2ecf20Sopenharmony_ci st->sndbuf[2] = wo ? wlen : rlen; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci if (wo) { 448c2ecf20Sopenharmony_ci memcpy(&st->sndbuf[3], wbuf, wlen); 458c2ecf20Sopenharmony_ci ret = dvb_usb_generic_write(d, st->sndbuf, 7); 468c2ecf20Sopenharmony_ci } else { 478c2ecf20Sopenharmony_ci ret = dvb_usb_generic_rw(d, st->sndbuf, 7, st->rcvbuf, 7, 10); 488c2ecf20Sopenharmony_ci memcpy(rbuf, &st->rcvbuf[3], rlen); 498c2ecf20Sopenharmony_ci } 508c2ecf20Sopenharmony_ci return ret; 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* I2C */ 548c2ecf20Sopenharmony_cistatic int digitv_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci struct dvb_usb_device *d = i2c_get_adapdata(adap); 578c2ecf20Sopenharmony_ci int i; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&d->i2c_mutex) < 0) 608c2ecf20Sopenharmony_ci return -EAGAIN; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci if (num > 2) 638c2ecf20Sopenharmony_ci warn("more than 2 i2c messages at a time is not handled yet. TODO."); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci for (i = 0; i < num; i++) { 668c2ecf20Sopenharmony_ci if (msg[i].len < 1) { 678c2ecf20Sopenharmony_ci i = -EOPNOTSUPP; 688c2ecf20Sopenharmony_ci break; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci /* write/read request */ 718c2ecf20Sopenharmony_ci if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { 728c2ecf20Sopenharmony_ci if (digitv_ctrl_msg(d, USB_READ_COFDM, msg[i].buf[0], NULL, 0, 738c2ecf20Sopenharmony_ci msg[i+1].buf,msg[i+1].len) < 0) 748c2ecf20Sopenharmony_ci break; 758c2ecf20Sopenharmony_ci i++; 768c2ecf20Sopenharmony_ci } else 778c2ecf20Sopenharmony_ci if (digitv_ctrl_msg(d,USB_WRITE_COFDM, msg[i].buf[0], 788c2ecf20Sopenharmony_ci &msg[i].buf[1],msg[i].len-1,NULL,0) < 0) 798c2ecf20Sopenharmony_ci break; 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci mutex_unlock(&d->i2c_mutex); 838c2ecf20Sopenharmony_ci return i; 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic u32 digitv_i2c_func(struct i2c_adapter *adapter) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci return I2C_FUNC_I2C; 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic struct i2c_algorithm digitv_i2c_algo = { 928c2ecf20Sopenharmony_ci .master_xfer = digitv_i2c_xfer, 938c2ecf20Sopenharmony_ci .functionality = digitv_i2c_func, 948c2ecf20Sopenharmony_ci}; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci/* Callbacks for DVB USB */ 978c2ecf20Sopenharmony_cistatic int digitv_identify_state(struct usb_device *udev, 988c2ecf20Sopenharmony_ci const struct dvb_usb_device_properties *props, 998c2ecf20Sopenharmony_ci const struct dvb_usb_device_description **desc, 1008c2ecf20Sopenharmony_ci int *cold) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci *cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0; 1038c2ecf20Sopenharmony_ci return 0; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic int digitv_mt352_demod_init(struct dvb_frontend *fe) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci static u8 reset_buf[] = { 0x89, 0x38, 0x8a, 0x2d, 0x50, 0x80 }; 1098c2ecf20Sopenharmony_ci static u8 init_buf[] = { 0x68, 0xa0, 0x8e, 0x40, 0x53, 0x50, 1108c2ecf20Sopenharmony_ci 0x67, 0x20, 0x7d, 0x01, 0x7c, 0x00, 0x7a, 0x00, 1118c2ecf20Sopenharmony_ci 0x79, 0x20, 0x57, 0x05, 0x56, 0x31, 0x88, 0x0f, 1128c2ecf20Sopenharmony_ci 0x75, 0x32 }; 1138c2ecf20Sopenharmony_ci int i; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(reset_buf); i += 2) 1168c2ecf20Sopenharmony_ci mt352_write(fe, &reset_buf[i], 2); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci msleep(1); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(init_buf); i += 2) 1218c2ecf20Sopenharmony_ci mt352_write(fe, &init_buf[i], 2); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci return 0; 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic struct mt352_config digitv_mt352_config = { 1278c2ecf20Sopenharmony_ci .demod_init = digitv_mt352_demod_init, 1288c2ecf20Sopenharmony_ci}; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci struct dvb_usb_adapter *adap = fe->dvb->priv; 1338c2ecf20Sopenharmony_ci u8 b[5]; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci fe->ops.tuner_ops.calc_regs(fe, b, sizeof(b)); 1368c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 1378c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 1388c2ecf20Sopenharmony_ci return digitv_ctrl_msg(adap->dev, USB_WRITE_TUNER, 0, &b[1], 4, NULL, 0); 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic struct nxt6000_config digitv_nxt6000_config = { 1428c2ecf20Sopenharmony_ci .clock_inversion = 1, 1438c2ecf20Sopenharmony_ci}; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic int digitv_frontend_attach(struct dvb_usb_adapter *adap) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci struct digitv_state *st = adap->dev->priv; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci adap->fe_adap[0].fe = dvb_attach(mt352_attach, &digitv_mt352_config, 1508c2ecf20Sopenharmony_ci &adap->dev->i2c_adap); 1518c2ecf20Sopenharmony_ci if ((adap->fe_adap[0].fe) != NULL) { 1528c2ecf20Sopenharmony_ci st->is_nxt6000 = 0; 1538c2ecf20Sopenharmony_ci return 0; 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci adap->fe_adap[0].fe = dvb_attach(nxt6000_attach, 1568c2ecf20Sopenharmony_ci &digitv_nxt6000_config, 1578c2ecf20Sopenharmony_ci &adap->dev->i2c_adap); 1588c2ecf20Sopenharmony_ci if ((adap->fe_adap[0].fe) != NULL) { 1598c2ecf20Sopenharmony_ci st->is_nxt6000 = 1; 1608c2ecf20Sopenharmony_ci return 0; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci return -EIO; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic int digitv_tuner_attach(struct dvb_usb_adapter *adap) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci struct digitv_state *st = adap->dev->priv; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (!dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, NULL, DVB_PLL_TDED4)) 1708c2ecf20Sopenharmony_ci return -ENODEV; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (st->is_nxt6000) 1738c2ecf20Sopenharmony_ci adap->fe_adap[0].fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci return 0; 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistatic struct rc_map_table rc_map_digitv_table[] = { 1798c2ecf20Sopenharmony_ci { 0x5f55, KEY_0 }, 1808c2ecf20Sopenharmony_ci { 0x6f55, KEY_1 }, 1818c2ecf20Sopenharmony_ci { 0x9f55, KEY_2 }, 1828c2ecf20Sopenharmony_ci { 0xaf55, KEY_3 }, 1838c2ecf20Sopenharmony_ci { 0x5f56, KEY_4 }, 1848c2ecf20Sopenharmony_ci { 0x6f56, KEY_5 }, 1858c2ecf20Sopenharmony_ci { 0x9f56, KEY_6 }, 1868c2ecf20Sopenharmony_ci { 0xaf56, KEY_7 }, 1878c2ecf20Sopenharmony_ci { 0x5f59, KEY_8 }, 1888c2ecf20Sopenharmony_ci { 0x6f59, KEY_9 }, 1898c2ecf20Sopenharmony_ci { 0x9f59, KEY_TV }, 1908c2ecf20Sopenharmony_ci { 0xaf59, KEY_AUX }, 1918c2ecf20Sopenharmony_ci { 0x5f5a, KEY_DVD }, 1928c2ecf20Sopenharmony_ci { 0x6f5a, KEY_POWER }, 1938c2ecf20Sopenharmony_ci { 0x9f5a, KEY_CAMERA }, /* labelled 'Picture' */ 1948c2ecf20Sopenharmony_ci { 0xaf5a, KEY_AUDIO }, 1958c2ecf20Sopenharmony_ci { 0x5f65, KEY_INFO }, 1968c2ecf20Sopenharmony_ci { 0x6f65, KEY_F13 }, /* 16:9 */ 1978c2ecf20Sopenharmony_ci { 0x9f65, KEY_F14 }, /* 14:9 */ 1988c2ecf20Sopenharmony_ci { 0xaf65, KEY_EPG }, 1998c2ecf20Sopenharmony_ci { 0x5f66, KEY_EXIT }, 2008c2ecf20Sopenharmony_ci { 0x6f66, KEY_MENU }, 2018c2ecf20Sopenharmony_ci { 0x9f66, KEY_UP }, 2028c2ecf20Sopenharmony_ci { 0xaf66, KEY_DOWN }, 2038c2ecf20Sopenharmony_ci { 0x5f69, KEY_LEFT }, 2048c2ecf20Sopenharmony_ci { 0x6f69, KEY_RIGHT }, 2058c2ecf20Sopenharmony_ci { 0x9f69, KEY_ENTER }, 2068c2ecf20Sopenharmony_ci { 0xaf69, KEY_CHANNELUP }, 2078c2ecf20Sopenharmony_ci { 0x5f6a, KEY_CHANNELDOWN }, 2088c2ecf20Sopenharmony_ci { 0x6f6a, KEY_VOLUMEUP }, 2098c2ecf20Sopenharmony_ci { 0x9f6a, KEY_VOLUMEDOWN }, 2108c2ecf20Sopenharmony_ci { 0xaf6a, KEY_RED }, 2118c2ecf20Sopenharmony_ci { 0x5f95, KEY_GREEN }, 2128c2ecf20Sopenharmony_ci { 0x6f95, KEY_YELLOW }, 2138c2ecf20Sopenharmony_ci { 0x9f95, KEY_BLUE }, 2148c2ecf20Sopenharmony_ci { 0xaf95, KEY_SUBTITLE }, 2158c2ecf20Sopenharmony_ci { 0x5f96, KEY_F15 }, /* AD */ 2168c2ecf20Sopenharmony_ci { 0x6f96, KEY_TEXT }, 2178c2ecf20Sopenharmony_ci { 0x9f96, KEY_MUTE }, 2188c2ecf20Sopenharmony_ci { 0xaf96, KEY_REWIND }, 2198c2ecf20Sopenharmony_ci { 0x5f99, KEY_STOP }, 2208c2ecf20Sopenharmony_ci { 0x6f99, KEY_PLAY }, 2218c2ecf20Sopenharmony_ci { 0x9f99, KEY_FASTFORWARD }, 2228c2ecf20Sopenharmony_ci { 0xaf99, KEY_F16 }, /* chapter */ 2238c2ecf20Sopenharmony_ci { 0x5f9a, KEY_PAUSE }, 2248c2ecf20Sopenharmony_ci { 0x6f9a, KEY_PLAY }, 2258c2ecf20Sopenharmony_ci { 0x9f9a, KEY_RECORD }, 2268c2ecf20Sopenharmony_ci { 0xaf9a, KEY_F17 }, /* picture in picture */ 2278c2ecf20Sopenharmony_ci { 0x5fa5, KEY_KPPLUS }, /* zoom in */ 2288c2ecf20Sopenharmony_ci { 0x6fa5, KEY_KPMINUS }, /* zoom out */ 2298c2ecf20Sopenharmony_ci { 0x9fa5, KEY_F18 }, /* capture */ 2308c2ecf20Sopenharmony_ci { 0xafa5, KEY_F19 }, /* web */ 2318c2ecf20Sopenharmony_ci { 0x5fa6, KEY_EMAIL }, 2328c2ecf20Sopenharmony_ci { 0x6fa6, KEY_PHONE }, 2338c2ecf20Sopenharmony_ci { 0x9fa6, KEY_PC }, 2348c2ecf20Sopenharmony_ci}; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci struct rc_map_table *entry; 2398c2ecf20Sopenharmony_ci int ret, i; 2408c2ecf20Sopenharmony_ci u8 key[4]; 2418c2ecf20Sopenharmony_ci u8 b[4] = { 0 }; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci *event = 0; 2448c2ecf20Sopenharmony_ci *state = REMOTE_NO_KEY_PRESSED; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci ret = digitv_ctrl_msg(d, USB_READ_REMOTE, 0, NULL, 0, key, 4); 2478c2ecf20Sopenharmony_ci if (ret) 2488c2ecf20Sopenharmony_ci return ret; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci /* Tell the device we've read the remote. Not sure how necessary 2518c2ecf20Sopenharmony_ci this is, but the Nebula SDK does it. */ 2528c2ecf20Sopenharmony_ci ret = digitv_ctrl_msg(d, USB_WRITE_REMOTE, 0, b, 4, NULL, 0); 2538c2ecf20Sopenharmony_ci if (ret) 2548c2ecf20Sopenharmony_ci return ret; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci /* if something is inside the buffer, simulate key press */ 2578c2ecf20Sopenharmony_ci if (key[0] != 0) { 2588c2ecf20Sopenharmony_ci for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) { 2598c2ecf20Sopenharmony_ci entry = &d->props.rc.legacy.rc_map_table[i]; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (rc5_custom(entry) == key[0] && 2628c2ecf20Sopenharmony_ci rc5_data(entry) == key[1]) { 2638c2ecf20Sopenharmony_ci *event = entry->keycode; 2648c2ecf20Sopenharmony_ci *state = REMOTE_KEY_PRESSED; 2658c2ecf20Sopenharmony_ci return 0; 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci deb_rc("key: %*ph\n", 4, key); 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci return 0; 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci/* DVB USB Driver stuff */ 2768c2ecf20Sopenharmony_cistatic struct dvb_usb_device_properties digitv_properties; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic int digitv_probe(struct usb_interface *intf, 2798c2ecf20Sopenharmony_ci const struct usb_device_id *id) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci struct dvb_usb_device *d; 2828c2ecf20Sopenharmony_ci int ret = dvb_usb_device_init(intf, &digitv_properties, THIS_MODULE, &d, 2838c2ecf20Sopenharmony_ci adapter_nr); 2848c2ecf20Sopenharmony_ci if (ret == 0) { 2858c2ecf20Sopenharmony_ci u8 b[4] = { 0 }; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci if (d != NULL) { /* do that only when the firmware is loaded */ 2888c2ecf20Sopenharmony_ci b[0] = 1; 2898c2ecf20Sopenharmony_ci digitv_ctrl_msg(d,USB_WRITE_REMOTE_TYPE,0,b,4,NULL,0); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci b[0] = 0; 2928c2ecf20Sopenharmony_ci digitv_ctrl_msg(d,USB_WRITE_REMOTE,0,b,4,NULL,0); 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci return ret; 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cistatic struct usb_device_id digitv_table [] = { 2998c2ecf20Sopenharmony_ci { USB_DEVICE(USB_VID_ANCHOR, USB_PID_NEBULA_DIGITV) }, 3008c2ecf20Sopenharmony_ci { } /* Terminating entry */ 3018c2ecf20Sopenharmony_ci}; 3028c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE (usb, digitv_table); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic struct dvb_usb_device_properties digitv_properties = { 3058c2ecf20Sopenharmony_ci .caps = DVB_USB_IS_AN_I2C_ADAPTER, 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci .usb_ctrl = CYPRESS_FX2, 3088c2ecf20Sopenharmony_ci .firmware = "dvb-usb-digitv-02.fw", 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci .size_of_priv = sizeof(struct digitv_state), 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci .num_adapters = 1, 3138c2ecf20Sopenharmony_ci .adapter = { 3148c2ecf20Sopenharmony_ci { 3158c2ecf20Sopenharmony_ci .num_frontends = 1, 3168c2ecf20Sopenharmony_ci .fe = {{ 3178c2ecf20Sopenharmony_ci .frontend_attach = digitv_frontend_attach, 3188c2ecf20Sopenharmony_ci .tuner_attach = digitv_tuner_attach, 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci /* parameter for the MPEG2-data transfer */ 3218c2ecf20Sopenharmony_ci .stream = { 3228c2ecf20Sopenharmony_ci .type = USB_BULK, 3238c2ecf20Sopenharmony_ci .count = 7, 3248c2ecf20Sopenharmony_ci .endpoint = 0x02, 3258c2ecf20Sopenharmony_ci .u = { 3268c2ecf20Sopenharmony_ci .bulk = { 3278c2ecf20Sopenharmony_ci .buffersize = 4096, 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci }, 3318c2ecf20Sopenharmony_ci }}, 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci }, 3348c2ecf20Sopenharmony_ci .identify_state = digitv_identify_state, 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci .rc.legacy = { 3378c2ecf20Sopenharmony_ci .rc_interval = 1000, 3388c2ecf20Sopenharmony_ci .rc_map_table = rc_map_digitv_table, 3398c2ecf20Sopenharmony_ci .rc_map_size = ARRAY_SIZE(rc_map_digitv_table), 3408c2ecf20Sopenharmony_ci .rc_query = digitv_rc_query, 3418c2ecf20Sopenharmony_ci }, 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci .i2c_algo = &digitv_i2c_algo, 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci .generic_bulk_ctrl_endpoint = 0x01, 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci .num_device_descs = 1, 3488c2ecf20Sopenharmony_ci .devices = { 3498c2ecf20Sopenharmony_ci { "Nebula Electronics uDigiTV DVB-T USB2.0)", 3508c2ecf20Sopenharmony_ci { &digitv_table[0], NULL }, 3518c2ecf20Sopenharmony_ci { NULL }, 3528c2ecf20Sopenharmony_ci }, 3538c2ecf20Sopenharmony_ci { NULL }, 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci}; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistatic struct usb_driver digitv_driver = { 3588c2ecf20Sopenharmony_ci .name = "dvb_usb_digitv", 3598c2ecf20Sopenharmony_ci .probe = digitv_probe, 3608c2ecf20Sopenharmony_ci .disconnect = dvb_usb_device_exit, 3618c2ecf20Sopenharmony_ci .id_table = digitv_table, 3628c2ecf20Sopenharmony_ci}; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_cimodule_usb_driver(digitv_driver); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ciMODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>"); 3678c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Driver for Nebula Electronics uDigiTV DVB-T USB2.0"); 3688c2ecf20Sopenharmony_ciMODULE_VERSION("1.0-alpha"); 3698c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 370