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/media/dvb-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 u8 key; 100 vp7045_usb_op(d,RC_VAL_READ,NULL,0,&key,1,20); 101 102 deb_rc("remote query key: %x %d\n",key,key); 103 104 if (key != 0x44) { 105 /* 106 * The 8 bit address isn't available, but since the remote uses 107 * address 0 we'll use that. nec repeats are ignored too, even 108 * though the remote sends them. 109 */ 110 rc_keydown(d->rc_dev, RC_PROTO_NEC, RC_SCANCODE_NEC(0, key), 0); 111 } 112 113 return 0; 114 } 115 116 static int vp7045_read_eeprom(struct dvb_usb_device *d,u8 *buf, int len, int offset) 117 { 118 int i = 0; 119 u8 v,br[2]; 120 for (i=0; i < len; i++) { 121 v = offset + i; 122 vp7045_usb_op(d,GET_EE_VALUE,&v,1,br,2,5); 123 buf[i] = br[1]; 124 } 125 deb_info("VP7045 EEPROM read (offs: %d, len: %d) : ",offset, i); 126 debug_dump(buf,i,deb_info); 127 return 0; 128 } 129 130 static int vp7045_read_mac_addr(struct dvb_usb_device *d,u8 mac[6]) 131 { 132 return vp7045_read_eeprom(d,mac, 6, MAC_0_ADDR); 133 } 134 135 static int vp7045_frontend_attach(struct dvb_usb_adapter *adap) 136 { 137 u8 buf[255] = { 0 }; 138 139 vp7045_usb_op(adap->dev,VENDOR_STRING_READ,NULL,0,buf,20,0); 140 buf[10] = '\0'; 141 deb_info("firmware says: %s ",buf); 142 143 vp7045_usb_op(adap->dev,PRODUCT_STRING_READ,NULL,0,buf,20,0); 144 buf[10] = '\0'; 145 deb_info("%s ",buf); 146 147 vp7045_usb_op(adap->dev,FW_VERSION_READ,NULL,0,buf,20,0); 148 buf[10] = '\0'; 149 deb_info("v%s\n",buf); 150 151 /* Dump the EEPROM */ 152 /* vp7045_read_eeprom(d,buf, 255, FX2_ID_ADDR); */ 153 154 adap->fe_adap[0].fe = vp7045_fe_attach(adap->dev); 155 156 return 0; 157 } 158 159 static struct dvb_usb_device_properties vp7045_properties; 160 161 static int vp7045_usb_probe(struct usb_interface *intf, 162 const struct usb_device_id *id) 163 { 164 return dvb_usb_device_init(intf, &vp7045_properties, 165 THIS_MODULE, NULL, adapter_nr); 166 } 167 168 static struct usb_device_id vp7045_usb_table [] = { 169 { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7045_COLD) }, 170 { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7045_WARM) }, 171 { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_DNTV_TINYUSB2_COLD) }, 172 { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_DNTV_TINYUSB2_WARM) }, 173 { 0 }, 174 }; 175 MODULE_DEVICE_TABLE(usb, vp7045_usb_table); 176 177 static struct dvb_usb_device_properties vp7045_properties = { 178 .usb_ctrl = CYPRESS_FX2, 179 .firmware = "dvb-usb-vp7045-01.fw", 180 .size_of_priv = 20, 181 182 .num_adapters = 1, 183 .adapter = { 184 { 185 .num_frontends = 1, 186 .fe = {{ 187 .frontend_attach = vp7045_frontend_attach, 188 /* parameter for the MPEG2-data transfer */ 189 .stream = { 190 .type = USB_BULK, 191 .count = 7, 192 .endpoint = 0x02, 193 .u = { 194 .bulk = { 195 .buffersize = 4096, 196 } 197 } 198 }, 199 }}, 200 } 201 }, 202 .power_ctrl = vp7045_power_ctrl, 203 .read_mac_address = vp7045_read_mac_addr, 204 205 .rc.core = { 206 .rc_interval = 400, 207 .rc_codes = RC_MAP_TWINHAN_VP1027_DVBS, 208 .module_name = KBUILD_MODNAME, 209 .rc_query = vp7045_rc_query, 210 .allowed_protos = RC_PROTO_BIT_NEC, 211 .scancode_mask = 0xff, 212 }, 213 214 .num_device_descs = 2, 215 .devices = { 216 { .name = "Twinhan USB2.0 DVB-T receiver (TwinhanDTV Alpha/MagicBox II)", 217 .cold_ids = { &vp7045_usb_table[0], NULL }, 218 .warm_ids = { &vp7045_usb_table[1], NULL }, 219 }, 220 { .name = "DigitalNow TinyUSB 2 DVB-t Receiver", 221 .cold_ids = { &vp7045_usb_table[2], NULL }, 222 .warm_ids = { &vp7045_usb_table[3], NULL }, 223 }, 224 { NULL }, 225 } 226 }; 227 228 /* usb specific object needed to register this driver with the usb subsystem */ 229 static struct usb_driver vp7045_usb_driver = { 230 .name = "dvb_usb_vp7045", 231 .probe = vp7045_usb_probe, 232 .disconnect = dvb_usb_device_exit, 233 .id_table = vp7045_usb_table, 234 }; 235 236 module_usb_driver(vp7045_usb_driver); 237 238 MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>"); 239 MODULE_DESCRIPTION("Driver for Twinhan MagicBox/Alpha and DNTV tinyUSB2 DVB-T USB2.0"); 240 MODULE_VERSION("1.0"); 241 MODULE_LICENSE("GPL"); 242