257 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* DVB USB compliant Linux driver for the3 * - TwinhanDTV Alpha/MagicBoxII USB2.0 DVB-T receiver4 * - DigitalNow TinyUSB2 DVB-t receiver5 *6 * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@posteo.de)7 *8 * Thanks to Twinhan who kindly provided hardware and information.9 *10 * see Documentation/driver-api/media/drivers/dvb-usb.rst for more information11 */12#include "vp7045.h"13 14/* debug */15static int dvb_usb_vp7045_debug;16module_param_named(debug,dvb_usb_vp7045_debug, int, 0644);17MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);18 19DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);20 21#define deb_info(args...) dprintk(dvb_usb_vp7045_debug,0x01,args)22#define deb_xfer(args...) dprintk(dvb_usb_vp7045_debug,0x02,args)23#define deb_rc(args...) dprintk(dvb_usb_vp7045_debug,0x04,args)24 25int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, int inlen, int msec)26{27 int ret = 0;28 u8 *buf = d->priv;29 30 buf[0] = cmd;31 32 if (outlen > 19)33 outlen = 19;34 35 if (inlen > 11)36 inlen = 11;37 38 ret = mutex_lock_interruptible(&d->usb_mutex);39 if (ret)40 return ret;41 42 if (out != NULL && outlen > 0)43 memcpy(&buf[1], out, outlen);44 45 deb_xfer("out buffer: ");46 debug_dump(buf, outlen+1, deb_xfer);47 48 49 if (usb_control_msg(d->udev,50 usb_sndctrlpipe(d->udev,0),51 TH_COMMAND_OUT, USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0,52 buf, 20, 2000) != 20) {53 err("USB control message 'out' went wrong.");54 ret = -EIO;55 goto unlock;56 }57 58 msleep(msec);59 60 if (usb_control_msg(d->udev,61 usb_rcvctrlpipe(d->udev,0),62 TH_COMMAND_IN, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,63 buf, 12, 2000) != 12) {64 err("USB control message 'in' went wrong.");65 ret = -EIO;66 goto unlock;67 }68 69 deb_xfer("in buffer: ");70 debug_dump(buf, 12, deb_xfer);71 72 if (in != NULL && inlen > 0)73 memcpy(in, &buf[1], inlen);74 75unlock:76 mutex_unlock(&d->usb_mutex);77 78 return ret;79}80 81u8 vp7045_read_reg(struct dvb_usb_device *d, u8 reg)82{83 u8 obuf[2] = { 0 },v;84 obuf[1] = reg;85 86 vp7045_usb_op(d,TUNER_REG_READ,obuf,2,&v,1,30);87 88 return v;89}90 91static int vp7045_power_ctrl(struct dvb_usb_device *d, int onoff)92{93 u8 v = onoff;94 return vp7045_usb_op(d,SET_TUNER_POWER,&v,1,NULL,0,150);95}96 97static int vp7045_rc_query(struct dvb_usb_device *d)98{99 int ret;100 u8 key;101 102 ret = vp7045_usb_op(d, RC_VAL_READ, NULL, 0, &key, 1, 20);103 if (ret)104 return ret;105 106 deb_rc("remote query key: %x\n", key);107 108 if (key != 0x44) {109 /*110 * The 8 bit address isn't available, but since the remote uses111 * address 0 we'll use that. nec repeats are ignored too, even112 * though the remote sends them.113 */114 rc_keydown(d->rc_dev, RC_PROTO_NEC, RC_SCANCODE_NEC(0, key), 0);115 }116 117 return 0;118}119 120static int vp7045_read_eeprom(struct dvb_usb_device *d,u8 *buf, int len, int offset)121{122 int i, ret;123 u8 v, br[2];124 for (i=0; i < len; i++) {125 v = offset + i;126 ret = vp7045_usb_op(d, GET_EE_VALUE, &v, 1, br, 2, 5);127 if (ret)128 return ret;129 130 buf[i] = br[1];131 }132 deb_info("VP7045 EEPROM read (offs: %d, len: %d) : ", offset, i);133 debug_dump(buf, i, deb_info);134 return 0;135}136 137static int vp7045_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])138{139 return vp7045_read_eeprom(d,mac, 6, MAC_0_ADDR);140}141 142static int vp7045_frontend_attach(struct dvb_usb_adapter *adap)143{144 u8 buf[255] = { 0 };145 146 vp7045_usb_op(adap->dev,VENDOR_STRING_READ,NULL,0,buf,20,0);147 buf[10] = '\0';148 deb_info("firmware says: %s ",buf);149 150 vp7045_usb_op(adap->dev,PRODUCT_STRING_READ,NULL,0,buf,20,0);151 buf[10] = '\0';152 deb_info("%s ",buf);153 154 vp7045_usb_op(adap->dev,FW_VERSION_READ,NULL,0,buf,20,0);155 buf[10] = '\0';156 deb_info("v%s\n",buf);157 158/* Dump the EEPROM */159/* vp7045_read_eeprom(d,buf, 255, FX2_ID_ADDR); */160 161 adap->fe_adap[0].fe = vp7045_fe_attach(adap->dev);162 163 return 0;164}165 166static struct dvb_usb_device_properties vp7045_properties;167 168static int vp7045_usb_probe(struct usb_interface *intf,169 const struct usb_device_id *id)170{171 return dvb_usb_device_init(intf, &vp7045_properties,172 THIS_MODULE, NULL, adapter_nr);173}174 175enum {176 VISIONPLUS_VP7045_COLD,177 VISIONPLUS_VP7045_WARM,178 VISIONPLUS_TINYUSB2_COLD,179 VISIONPLUS_TINYUSB2_WARM,180};181 182static struct usb_device_id vp7045_usb_table[] = {183 DVB_USB_DEV(VISIONPLUS, VISIONPLUS_VP7045_COLD),184 DVB_USB_DEV(VISIONPLUS, VISIONPLUS_VP7045_WARM),185 DVB_USB_DEV(VISIONPLUS, VISIONPLUS_TINYUSB2_COLD),186 DVB_USB_DEV(VISIONPLUS, VISIONPLUS_TINYUSB2_WARM),187 { }188};189 190MODULE_DEVICE_TABLE(usb, vp7045_usb_table);191 192static struct dvb_usb_device_properties vp7045_properties = {193 .usb_ctrl = CYPRESS_FX2,194 .firmware = "dvb-usb-vp7045-01.fw",195 .size_of_priv = 20,196 197 .num_adapters = 1,198 .adapter = {199 {200 .num_frontends = 1,201 .fe = {{202 .frontend_attach = vp7045_frontend_attach,203 /* parameter for the MPEG2-data transfer */204 .stream = {205 .type = USB_BULK,206 .count = 7,207 .endpoint = 0x02,208 .u = {209 .bulk = {210 .buffersize = 4096,211 }212 }213 },214 }},215 }216 },217 .power_ctrl = vp7045_power_ctrl,218 .read_mac_address = vp7045_read_mac_addr,219 220 .rc.core = {221 .rc_interval = 400,222 .rc_codes = RC_MAP_TWINHAN_VP1027_DVBS,223 .module_name = KBUILD_MODNAME,224 .rc_query = vp7045_rc_query,225 .allowed_protos = RC_PROTO_BIT_NEC,226 .scancode_mask = 0xff,227 },228 229 .num_device_descs = 2,230 .devices = {231 { .name = "Twinhan USB2.0 DVB-T receiver (TwinhanDTV Alpha/MagicBox II)",232 .cold_ids = { &vp7045_usb_table[VISIONPLUS_VP7045_COLD], NULL },233 .warm_ids = { &vp7045_usb_table[VISIONPLUS_VP7045_WARM], NULL },234 },235 { .name = "DigitalNow TinyUSB 2 DVB-t Receiver",236 .cold_ids = { &vp7045_usb_table[VISIONPLUS_TINYUSB2_COLD], NULL },237 .warm_ids = { &vp7045_usb_table[VISIONPLUS_TINYUSB2_WARM], NULL },238 },239 { NULL },240 }241};242 243/* usb specific object needed to register this driver with the usb subsystem */244static struct usb_driver vp7045_usb_driver = {245 .name = "dvb_usb_vp7045",246 .probe = vp7045_usb_probe,247 .disconnect = dvb_usb_device_exit,248 .id_table = vp7045_usb_table,249};250 251module_usb_driver(vp7045_usb_driver);252 253MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");254MODULE_DESCRIPTION("Driver for Twinhan MagicBox/Alpha and DNTV tinyUSB2 DVB-T USB2.0");255MODULE_VERSION("1.0");256MODULE_LICENSE("GPL");257