1 // SPDX-License-Identifier: GPL-2.0-only 2 /* DVB USB compliant Linux driver for the 3 * - TwinhanDTV Alpha/MagicBoxII USB2.0 DVB-T receiver 4 * - DigitalNow TinyUSB2 DVB-t receiver 5 * 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 information 11 */ 12 #include "vp7045.h" 13 14 /* debug */ 15 static int dvb_usb_vp7045_debug; 16 module_param_named(debug,dvb_usb_vp7045_debug, int, 0644); 17 MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS); 18 19 DVB_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 25 int 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 75 unlock: 76 mutex_unlock(&d->usb_mutex); 77 78 return ret; 79 } 80 81 u8 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 91 static 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 97 static 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 uses 111 * address 0 we'll use that. nec repeats are ignored too, even 112 * 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 120 static 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 137 static 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 142 static 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 166 static struct dvb_usb_device_properties vp7045_properties; 167 168 static 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 175 static struct usb_device_id vp7045_usb_table [] = { 176 { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7045_COLD) }, 177 { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7045_WARM) }, 178 { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_DNTV_TINYUSB2_COLD) }, 179 { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_DNTV_TINYUSB2_WARM) }, 180 { 0 }, 181 }; 182 MODULE_DEVICE_TABLE(usb, vp7045_usb_table); 183 184 static struct dvb_usb_device_properties vp7045_properties = { 185 .usb_ctrl = CYPRESS_FX2, 186 .firmware = "dvb-usb-vp7045-01.fw", 187 .size_of_priv = 20, 188 189 .num_adapters = 1, 190 .adapter = { 191 { 192 .num_frontends = 1, 193 .fe = {{ 194 .frontend_attach = vp7045_frontend_attach, 195 /* parameter for the MPEG2-data transfer */ 196 .stream = { 197 .type = USB_BULK, 198 .count = 7, 199 .endpoint = 0x02, 200 .u = { 201 .bulk = { 202 .buffersize = 4096, 203 } 204 } 205 }, 206 }}, 207 } 208 }, 209 .power_ctrl = vp7045_power_ctrl, 210 .read_mac_address = vp7045_read_mac_addr, 211 212 .rc.core = { 213 .rc_interval = 400, 214 .rc_codes = RC_MAP_TWINHAN_VP1027_DVBS, 215 .module_name = KBUILD_MODNAME, 216 .rc_query = vp7045_rc_query, 217 .allowed_protos = RC_PROTO_BIT_NEC, 218 .scancode_mask = 0xff, 219 }, 220 221 .num_device_descs = 2, 222 .devices = { 223 { .name = "Twinhan USB2.0 DVB-T receiver (TwinhanDTV Alpha/MagicBox II)", 224 .cold_ids = { &vp7045_usb_table[0], NULL }, 225 .warm_ids = { &vp7045_usb_table[1], NULL }, 226 }, 227 { .name = "DigitalNow TinyUSB 2 DVB-t Receiver", 228 .cold_ids = { &vp7045_usb_table[2], NULL }, 229 .warm_ids = { &vp7045_usb_table[3], NULL }, 230 }, 231 { NULL }, 232 } 233 }; 234 235 /* usb specific object needed to register this driver with the usb subsystem */ 236 static struct usb_driver vp7045_usb_driver = { 237 .name = "dvb_usb_vp7045", 238 .probe = vp7045_usb_probe, 239 .disconnect = dvb_usb_device_exit, 240 .id_table = vp7045_usb_table, 241 }; 242 243 module_usb_driver(vp7045_usb_driver); 244 245 MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>"); 246 MODULE_DESCRIPTION("Driver for Twinhan MagicBox/Alpha and DNTV tinyUSB2 DVB-T USB2.0"); 247 MODULE_VERSION("1.0"); 248 MODULE_LICENSE("GPL"); 249