162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* DVB USB compliant linux driver for Nebula Electronics uDigiTV DVB-T USB2.0 362306a36Sopenharmony_ci * receiver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@posteo.de) 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * partly based on the SDK published by Nebula Electronics 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * see Documentation/driver-api/media/drivers/dvb-usb.rst for more information 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci#include "digitv.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include "mt352.h" 1462306a36Sopenharmony_ci#include "nxt6000.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci/* debug */ 1762306a36Sopenharmony_cistatic int dvb_usb_digitv_debug; 1862306a36Sopenharmony_cimodule_param_named(debug,dvb_usb_digitv_debug, int, 0644); 1962306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ciDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define deb_rc(args...) dprintk(dvb_usb_digitv_debug,0x01,args) 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic int digitv_ctrl_msg(struct dvb_usb_device *d, 2662306a36Sopenharmony_ci u8 cmd, u8 vv, u8 *wbuf, int wlen, u8 *rbuf, int rlen) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci struct digitv_state *st = d->priv; 2962306a36Sopenharmony_ci int ret, wo; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci wo = (rbuf == NULL || rlen == 0); /* write-only */ 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci if (wlen > 4 || rlen > 4) 3462306a36Sopenharmony_ci return -EIO; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci memset(st->sndbuf, 0, 7); 3762306a36Sopenharmony_ci memset(st->rcvbuf, 0, 7); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci st->sndbuf[0] = cmd; 4062306a36Sopenharmony_ci st->sndbuf[1] = vv; 4162306a36Sopenharmony_ci st->sndbuf[2] = wo ? wlen : rlen; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci if (wo) { 4462306a36Sopenharmony_ci memcpy(&st->sndbuf[3], wbuf, wlen); 4562306a36Sopenharmony_ci ret = dvb_usb_generic_write(d, st->sndbuf, 7); 4662306a36Sopenharmony_ci } else { 4762306a36Sopenharmony_ci ret = dvb_usb_generic_rw(d, st->sndbuf, 7, st->rcvbuf, 7, 10); 4862306a36Sopenharmony_ci memcpy(rbuf, &st->rcvbuf[3], rlen); 4962306a36Sopenharmony_ci } 5062306a36Sopenharmony_ci return ret; 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/* I2C */ 5462306a36Sopenharmony_cistatic int digitv_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci struct dvb_usb_device *d = i2c_get_adapdata(adap); 5762306a36Sopenharmony_ci int i; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci if (mutex_lock_interruptible(&d->i2c_mutex) < 0) 6062306a36Sopenharmony_ci return -EAGAIN; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci if (num > 2) 6362306a36Sopenharmony_ci warn("more than 2 i2c messages at a time is not handled yet. TODO."); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci for (i = 0; i < num; i++) { 6662306a36Sopenharmony_ci if (msg[i].len < 1) { 6762306a36Sopenharmony_ci i = -EOPNOTSUPP; 6862306a36Sopenharmony_ci break; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci /* write/read request */ 7162306a36Sopenharmony_ci if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { 7262306a36Sopenharmony_ci if (digitv_ctrl_msg(d, USB_READ_COFDM, msg[i].buf[0], NULL, 0, 7362306a36Sopenharmony_ci msg[i+1].buf,msg[i+1].len) < 0) 7462306a36Sopenharmony_ci break; 7562306a36Sopenharmony_ci i++; 7662306a36Sopenharmony_ci } else 7762306a36Sopenharmony_ci if (digitv_ctrl_msg(d,USB_WRITE_COFDM, msg[i].buf[0], 7862306a36Sopenharmony_ci &msg[i].buf[1],msg[i].len-1,NULL,0) < 0) 7962306a36Sopenharmony_ci break; 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci mutex_unlock(&d->i2c_mutex); 8362306a36Sopenharmony_ci return i; 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic u32 digitv_i2c_func(struct i2c_adapter *adapter) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci return I2C_FUNC_I2C; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic struct i2c_algorithm digitv_i2c_algo = { 9262306a36Sopenharmony_ci .master_xfer = digitv_i2c_xfer, 9362306a36Sopenharmony_ci .functionality = digitv_i2c_func, 9462306a36Sopenharmony_ci}; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci/* Callbacks for DVB USB */ 9762306a36Sopenharmony_cistatic int digitv_identify_state(struct usb_device *udev, 9862306a36Sopenharmony_ci const struct dvb_usb_device_properties *props, 9962306a36Sopenharmony_ci const struct dvb_usb_device_description **desc, 10062306a36Sopenharmony_ci int *cold) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci *cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0; 10362306a36Sopenharmony_ci return 0; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic int digitv_mt352_demod_init(struct dvb_frontend *fe) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci static u8 reset_buf[] = { 0x89, 0x38, 0x8a, 0x2d, 0x50, 0x80 }; 10962306a36Sopenharmony_ci static u8 init_buf[] = { 0x68, 0xa0, 0x8e, 0x40, 0x53, 0x50, 11062306a36Sopenharmony_ci 0x67, 0x20, 0x7d, 0x01, 0x7c, 0x00, 0x7a, 0x00, 11162306a36Sopenharmony_ci 0x79, 0x20, 0x57, 0x05, 0x56, 0x31, 0x88, 0x0f, 11262306a36Sopenharmony_ci 0x75, 0x32 }; 11362306a36Sopenharmony_ci int i; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(reset_buf); i += 2) 11662306a36Sopenharmony_ci mt352_write(fe, &reset_buf[i], 2); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci msleep(1); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(init_buf); i += 2) 12162306a36Sopenharmony_ci mt352_write(fe, &init_buf[i], 2); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci return 0; 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic struct mt352_config digitv_mt352_config = { 12762306a36Sopenharmony_ci .demod_init = digitv_mt352_demod_init, 12862306a36Sopenharmony_ci}; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci struct dvb_usb_adapter *adap = fe->dvb->priv; 13362306a36Sopenharmony_ci u8 b[5]; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci fe->ops.tuner_ops.calc_regs(fe, b, sizeof(b)); 13662306a36Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 13762306a36Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 13862306a36Sopenharmony_ci return digitv_ctrl_msg(adap->dev, USB_WRITE_TUNER, 0, &b[1], 4, NULL, 0); 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic struct nxt6000_config digitv_nxt6000_config = { 14262306a36Sopenharmony_ci .clock_inversion = 1, 14362306a36Sopenharmony_ci}; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic int digitv_frontend_attach(struct dvb_usb_adapter *adap) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci struct digitv_state *st = adap->dev->priv; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci adap->fe_adap[0].fe = dvb_attach(mt352_attach, &digitv_mt352_config, 15062306a36Sopenharmony_ci &adap->dev->i2c_adap); 15162306a36Sopenharmony_ci if ((adap->fe_adap[0].fe) != NULL) { 15262306a36Sopenharmony_ci st->is_nxt6000 = 0; 15362306a36Sopenharmony_ci return 0; 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci adap->fe_adap[0].fe = dvb_attach(nxt6000_attach, 15662306a36Sopenharmony_ci &digitv_nxt6000_config, 15762306a36Sopenharmony_ci &adap->dev->i2c_adap); 15862306a36Sopenharmony_ci if ((adap->fe_adap[0].fe) != NULL) { 15962306a36Sopenharmony_ci st->is_nxt6000 = 1; 16062306a36Sopenharmony_ci return 0; 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci return -EIO; 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic int digitv_tuner_attach(struct dvb_usb_adapter *adap) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci struct digitv_state *st = adap->dev->priv; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci if (!dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, NULL, DVB_PLL_TDED4)) 17062306a36Sopenharmony_ci return -ENODEV; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci if (st->is_nxt6000) 17362306a36Sopenharmony_ci adap->fe_adap[0].fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci return 0; 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cistatic struct rc_map_table rc_map_digitv_table[] = { 17962306a36Sopenharmony_ci { 0x5f55, KEY_0 }, 18062306a36Sopenharmony_ci { 0x6f55, KEY_1 }, 18162306a36Sopenharmony_ci { 0x9f55, KEY_2 }, 18262306a36Sopenharmony_ci { 0xaf55, KEY_3 }, 18362306a36Sopenharmony_ci { 0x5f56, KEY_4 }, 18462306a36Sopenharmony_ci { 0x6f56, KEY_5 }, 18562306a36Sopenharmony_ci { 0x9f56, KEY_6 }, 18662306a36Sopenharmony_ci { 0xaf56, KEY_7 }, 18762306a36Sopenharmony_ci { 0x5f59, KEY_8 }, 18862306a36Sopenharmony_ci { 0x6f59, KEY_9 }, 18962306a36Sopenharmony_ci { 0x9f59, KEY_TV }, 19062306a36Sopenharmony_ci { 0xaf59, KEY_AUX }, 19162306a36Sopenharmony_ci { 0x5f5a, KEY_DVD }, 19262306a36Sopenharmony_ci { 0x6f5a, KEY_POWER }, 19362306a36Sopenharmony_ci { 0x9f5a, KEY_CAMERA }, /* labelled 'Picture' */ 19462306a36Sopenharmony_ci { 0xaf5a, KEY_AUDIO }, 19562306a36Sopenharmony_ci { 0x5f65, KEY_INFO }, 19662306a36Sopenharmony_ci { 0x6f65, KEY_F13 }, /* 16:9 */ 19762306a36Sopenharmony_ci { 0x9f65, KEY_F14 }, /* 14:9 */ 19862306a36Sopenharmony_ci { 0xaf65, KEY_EPG }, 19962306a36Sopenharmony_ci { 0x5f66, KEY_EXIT }, 20062306a36Sopenharmony_ci { 0x6f66, KEY_MENU }, 20162306a36Sopenharmony_ci { 0x9f66, KEY_UP }, 20262306a36Sopenharmony_ci { 0xaf66, KEY_DOWN }, 20362306a36Sopenharmony_ci { 0x5f69, KEY_LEFT }, 20462306a36Sopenharmony_ci { 0x6f69, KEY_RIGHT }, 20562306a36Sopenharmony_ci { 0x9f69, KEY_ENTER }, 20662306a36Sopenharmony_ci { 0xaf69, KEY_CHANNELUP }, 20762306a36Sopenharmony_ci { 0x5f6a, KEY_CHANNELDOWN }, 20862306a36Sopenharmony_ci { 0x6f6a, KEY_VOLUMEUP }, 20962306a36Sopenharmony_ci { 0x9f6a, KEY_VOLUMEDOWN }, 21062306a36Sopenharmony_ci { 0xaf6a, KEY_RED }, 21162306a36Sopenharmony_ci { 0x5f95, KEY_GREEN }, 21262306a36Sopenharmony_ci { 0x6f95, KEY_YELLOW }, 21362306a36Sopenharmony_ci { 0x9f95, KEY_BLUE }, 21462306a36Sopenharmony_ci { 0xaf95, KEY_SUBTITLE }, 21562306a36Sopenharmony_ci { 0x5f96, KEY_F15 }, /* AD */ 21662306a36Sopenharmony_ci { 0x6f96, KEY_TEXT }, 21762306a36Sopenharmony_ci { 0x9f96, KEY_MUTE }, 21862306a36Sopenharmony_ci { 0xaf96, KEY_REWIND }, 21962306a36Sopenharmony_ci { 0x5f99, KEY_STOP }, 22062306a36Sopenharmony_ci { 0x6f99, KEY_PLAY }, 22162306a36Sopenharmony_ci { 0x9f99, KEY_FASTFORWARD }, 22262306a36Sopenharmony_ci { 0xaf99, KEY_F16 }, /* chapter */ 22362306a36Sopenharmony_ci { 0x5f9a, KEY_PAUSE }, 22462306a36Sopenharmony_ci { 0x6f9a, KEY_PLAY }, 22562306a36Sopenharmony_ci { 0x9f9a, KEY_RECORD }, 22662306a36Sopenharmony_ci { 0xaf9a, KEY_F17 }, /* picture in picture */ 22762306a36Sopenharmony_ci { 0x5fa5, KEY_KPPLUS }, /* zoom in */ 22862306a36Sopenharmony_ci { 0x6fa5, KEY_KPMINUS }, /* zoom out */ 22962306a36Sopenharmony_ci { 0x9fa5, KEY_F18 }, /* capture */ 23062306a36Sopenharmony_ci { 0xafa5, KEY_F19 }, /* web */ 23162306a36Sopenharmony_ci { 0x5fa6, KEY_EMAIL }, 23262306a36Sopenharmony_ci { 0x6fa6, KEY_PHONE }, 23362306a36Sopenharmony_ci { 0x9fa6, KEY_PC }, 23462306a36Sopenharmony_ci}; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci struct rc_map_table *entry; 23962306a36Sopenharmony_ci int ret, i; 24062306a36Sopenharmony_ci u8 key[4]; 24162306a36Sopenharmony_ci u8 b[4] = { 0 }; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci *event = 0; 24462306a36Sopenharmony_ci *state = REMOTE_NO_KEY_PRESSED; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci ret = digitv_ctrl_msg(d, USB_READ_REMOTE, 0, NULL, 0, key, 4); 24762306a36Sopenharmony_ci if (ret) 24862306a36Sopenharmony_ci return ret; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci /* Tell the device we've read the remote. Not sure how necessary 25162306a36Sopenharmony_ci this is, but the Nebula SDK does it. */ 25262306a36Sopenharmony_ci ret = digitv_ctrl_msg(d, USB_WRITE_REMOTE, 0, b, 4, NULL, 0); 25362306a36Sopenharmony_ci if (ret) 25462306a36Sopenharmony_ci return ret; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci /* if something is inside the buffer, simulate key press */ 25762306a36Sopenharmony_ci if (key[0] != 0) { 25862306a36Sopenharmony_ci for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) { 25962306a36Sopenharmony_ci entry = &d->props.rc.legacy.rc_map_table[i]; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci if (rc5_custom(entry) == key[0] && 26262306a36Sopenharmony_ci rc5_data(entry) == key[1]) { 26362306a36Sopenharmony_ci *event = entry->keycode; 26462306a36Sopenharmony_ci *state = REMOTE_KEY_PRESSED; 26562306a36Sopenharmony_ci return 0; 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci deb_rc("key: %*ph\n", 4, key); 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci return 0; 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci/* DVB USB Driver stuff */ 27662306a36Sopenharmony_cistatic struct dvb_usb_device_properties digitv_properties; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistatic int digitv_probe(struct usb_interface *intf, 27962306a36Sopenharmony_ci const struct usb_device_id *id) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci struct dvb_usb_device *d; 28262306a36Sopenharmony_ci int ret = dvb_usb_device_init(intf, &digitv_properties, THIS_MODULE, &d, 28362306a36Sopenharmony_ci adapter_nr); 28462306a36Sopenharmony_ci if (ret == 0) { 28562306a36Sopenharmony_ci u8 b[4] = { 0 }; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci if (d != NULL) { /* do that only when the firmware is loaded */ 28862306a36Sopenharmony_ci b[0] = 1; 28962306a36Sopenharmony_ci digitv_ctrl_msg(d,USB_WRITE_REMOTE_TYPE,0,b,4,NULL,0); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci b[0] = 0; 29262306a36Sopenharmony_ci digitv_ctrl_msg(d,USB_WRITE_REMOTE,0,b,4,NULL,0); 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci return ret; 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cienum { 29962306a36Sopenharmony_ci ANCHOR_NEBULA_DIGITV, 30062306a36Sopenharmony_ci}; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cistatic struct usb_device_id digitv_table[] = { 30362306a36Sopenharmony_ci DVB_USB_DEV(ANCHOR, ANCHOR_NEBULA_DIGITV), 30462306a36Sopenharmony_ci { } 30562306a36Sopenharmony_ci}; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ciMODULE_DEVICE_TABLE (usb, digitv_table); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_cistatic struct dvb_usb_device_properties digitv_properties = { 31062306a36Sopenharmony_ci .caps = DVB_USB_IS_AN_I2C_ADAPTER, 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci .usb_ctrl = CYPRESS_FX2, 31362306a36Sopenharmony_ci .firmware = "dvb-usb-digitv-02.fw", 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci .size_of_priv = sizeof(struct digitv_state), 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci .num_adapters = 1, 31862306a36Sopenharmony_ci .adapter = { 31962306a36Sopenharmony_ci { 32062306a36Sopenharmony_ci .num_frontends = 1, 32162306a36Sopenharmony_ci .fe = {{ 32262306a36Sopenharmony_ci .frontend_attach = digitv_frontend_attach, 32362306a36Sopenharmony_ci .tuner_attach = digitv_tuner_attach, 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci /* parameter for the MPEG2-data transfer */ 32662306a36Sopenharmony_ci .stream = { 32762306a36Sopenharmony_ci .type = USB_BULK, 32862306a36Sopenharmony_ci .count = 7, 32962306a36Sopenharmony_ci .endpoint = 0x02, 33062306a36Sopenharmony_ci .u = { 33162306a36Sopenharmony_ci .bulk = { 33262306a36Sopenharmony_ci .buffersize = 4096, 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci }, 33662306a36Sopenharmony_ci }}, 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci }, 33962306a36Sopenharmony_ci .identify_state = digitv_identify_state, 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci .rc.legacy = { 34262306a36Sopenharmony_ci .rc_interval = 1000, 34362306a36Sopenharmony_ci .rc_map_table = rc_map_digitv_table, 34462306a36Sopenharmony_ci .rc_map_size = ARRAY_SIZE(rc_map_digitv_table), 34562306a36Sopenharmony_ci .rc_query = digitv_rc_query, 34662306a36Sopenharmony_ci }, 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci .i2c_algo = &digitv_i2c_algo, 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci .generic_bulk_ctrl_endpoint = 0x01, 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci .num_device_descs = 1, 35362306a36Sopenharmony_ci .devices = { 35462306a36Sopenharmony_ci { "Nebula Electronics uDigiTV DVB-T USB2.0)", 35562306a36Sopenharmony_ci { &digitv_table[ANCHOR_NEBULA_DIGITV], NULL }, 35662306a36Sopenharmony_ci { NULL }, 35762306a36Sopenharmony_ci }, 35862306a36Sopenharmony_ci { NULL }, 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci}; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cistatic struct usb_driver digitv_driver = { 36362306a36Sopenharmony_ci .name = "dvb_usb_digitv", 36462306a36Sopenharmony_ci .probe = digitv_probe, 36562306a36Sopenharmony_ci .disconnect = dvb_usb_device_exit, 36662306a36Sopenharmony_ci .id_table = digitv_table, 36762306a36Sopenharmony_ci}; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cimodule_usb_driver(digitv_driver); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ciMODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>"); 37262306a36Sopenharmony_ciMODULE_DESCRIPTION("Driver for Nebula Electronics uDigiTV DVB-T USB2.0"); 37362306a36Sopenharmony_ciMODULE_VERSION("1.0-alpha"); 37462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 375