1786baecfSMauro Carvalho Chehab /* DVB USB compliant Linux driver for the Afatech 9005 2786baecfSMauro Carvalho Chehab * USB1.1 DVB-T receiver. 3786baecfSMauro Carvalho Chehab * 4786baecfSMauro Carvalho Chehab * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org) 5786baecfSMauro Carvalho Chehab * 6786baecfSMauro Carvalho Chehab * Thanks to Afatech who kindly provided information. 7786baecfSMauro Carvalho Chehab * 8786baecfSMauro Carvalho Chehab * This program is free software; you can redistribute it and/or modify 9786baecfSMauro Carvalho Chehab * it under the terms of the GNU General Public License as published by 10786baecfSMauro Carvalho Chehab * the Free Software Foundation; either version 2 of the License, or 11786baecfSMauro Carvalho Chehab * (at your option) any later version. 12786baecfSMauro Carvalho Chehab * 13786baecfSMauro Carvalho Chehab * This program is distributed in the hope that it will be useful, 14786baecfSMauro Carvalho Chehab * but WITHOUT ANY WARRANTY; without even the implied warranty of 15786baecfSMauro Carvalho Chehab * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16786baecfSMauro Carvalho Chehab * GNU General Public License for more details. 17786baecfSMauro Carvalho Chehab * 18786baecfSMauro Carvalho Chehab * You should have received a copy of the GNU General Public License 19786baecfSMauro Carvalho Chehab * along with this program; if not, write to the Free Software 20786baecfSMauro Carvalho Chehab * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21786baecfSMauro Carvalho Chehab * 22786baecfSMauro Carvalho Chehab * see Documentation/dvb/README.dvb-usb for more information 23786baecfSMauro Carvalho Chehab */ 24786baecfSMauro Carvalho Chehab #include "af9005.h" 25786baecfSMauro Carvalho Chehab 26786baecfSMauro Carvalho Chehab /* debug */ 27786baecfSMauro Carvalho Chehab int dvb_usb_af9005_debug; 28786baecfSMauro Carvalho Chehab module_param_named(debug, dvb_usb_af9005_debug, int, 0644); 29786baecfSMauro Carvalho Chehab MODULE_PARM_DESC(debug, 30786baecfSMauro Carvalho Chehab "set debugging level (1=info,xfer=2,rc=4,reg=8,i2c=16,fw=32 (or-able))." 31786baecfSMauro Carvalho Chehab DVB_USB_DEBUG_STATUS); 32786baecfSMauro Carvalho Chehab /* enable obnoxious led */ 3361f6a056SMauro Carvalho Chehab bool dvb_usb_af9005_led = true; 34786baecfSMauro Carvalho Chehab module_param_named(led, dvb_usb_af9005_led, bool, 0644); 35786baecfSMauro Carvalho Chehab MODULE_PARM_DESC(led, "enable led (default: 1)."); 36786baecfSMauro Carvalho Chehab 37786baecfSMauro Carvalho Chehab /* eeprom dump */ 38786baecfSMauro Carvalho Chehab static int dvb_usb_af9005_dump_eeprom; 39786baecfSMauro Carvalho Chehab module_param_named(dump_eeprom, dvb_usb_af9005_dump_eeprom, int, 0); 40786baecfSMauro Carvalho Chehab MODULE_PARM_DESC(dump_eeprom, "dump contents of the eeprom."); 41786baecfSMauro Carvalho Chehab 42786baecfSMauro Carvalho Chehab DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); 43786baecfSMauro Carvalho Chehab 44786baecfSMauro Carvalho Chehab /* remote control decoder */ 45786baecfSMauro Carvalho Chehab static int (*rc_decode) (struct dvb_usb_device *d, u8 *data, int len, 46786baecfSMauro Carvalho Chehab u32 *event, int *state); 47786baecfSMauro Carvalho Chehab static void *rc_keys; 48786baecfSMauro Carvalho Chehab static int *rc_keys_size; 49786baecfSMauro Carvalho Chehab 50786baecfSMauro Carvalho Chehab u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; 51786baecfSMauro Carvalho Chehab 52786baecfSMauro Carvalho Chehab struct af9005_device_state { 53786baecfSMauro Carvalho Chehab u8 sequence; 54786baecfSMauro Carvalho Chehab int led_state; 55c58b84eeSMauro Carvalho Chehab unsigned char data[256]; 56c58b84eeSMauro Carvalho Chehab struct mutex data_mutex; 57786baecfSMauro Carvalho Chehab }; 58786baecfSMauro Carvalho Chehab 59786baecfSMauro Carvalho Chehab static int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg, 60786baecfSMauro Carvalho Chehab int readwrite, int type, u8 * values, int len) 61786baecfSMauro Carvalho Chehab { 62786baecfSMauro Carvalho Chehab struct af9005_device_state *st = d->priv; 63c58b84eeSMauro Carvalho Chehab u8 command, seq; 64c58b84eeSMauro Carvalho Chehab int i, ret; 65786baecfSMauro Carvalho Chehab 66786baecfSMauro Carvalho Chehab if (len < 1) { 67786baecfSMauro Carvalho Chehab err("generic read/write, less than 1 byte. Makes no sense."); 68786baecfSMauro Carvalho Chehab return -EINVAL; 69786baecfSMauro Carvalho Chehab } 70786baecfSMauro Carvalho Chehab if (len > 8) { 71786baecfSMauro Carvalho Chehab err("generic read/write, more than 8 bytes. Not supported."); 72786baecfSMauro Carvalho Chehab return -EINVAL; 73786baecfSMauro Carvalho Chehab } 74786baecfSMauro Carvalho Chehab 75c58b84eeSMauro Carvalho Chehab mutex_lock(&st->data_mutex); 76c58b84eeSMauro Carvalho Chehab st->data[0] = 14; /* rest of buffer length low */ 77c58b84eeSMauro Carvalho Chehab st->data[1] = 0; /* rest of buffer length high */ 78786baecfSMauro Carvalho Chehab 79c58b84eeSMauro Carvalho Chehab st->data[2] = AF9005_REGISTER_RW; /* register operation */ 80c58b84eeSMauro Carvalho Chehab st->data[3] = 12; /* rest of buffer length */ 81786baecfSMauro Carvalho Chehab 82c58b84eeSMauro Carvalho Chehab st->data[4] = seq = st->sequence++; /* sequence number */ 83786baecfSMauro Carvalho Chehab 84c58b84eeSMauro Carvalho Chehab st->data[5] = (u8) (reg >> 8); /* register address */ 85c58b84eeSMauro Carvalho Chehab st->data[6] = (u8) (reg & 0xff); 86786baecfSMauro Carvalho Chehab 87786baecfSMauro Carvalho Chehab if (type == AF9005_OFDM_REG) { 88786baecfSMauro Carvalho Chehab command = AF9005_CMD_OFDM_REG; 89786baecfSMauro Carvalho Chehab } else { 90786baecfSMauro Carvalho Chehab command = AF9005_CMD_TUNER; 91786baecfSMauro Carvalho Chehab } 92786baecfSMauro Carvalho Chehab 93786baecfSMauro Carvalho Chehab if (len > 1) 94786baecfSMauro Carvalho Chehab command |= 95786baecfSMauro Carvalho Chehab AF9005_CMD_BURST | AF9005_CMD_AUTOINC | (len - 1) << 3; 96786baecfSMauro Carvalho Chehab command |= readwrite; 97786baecfSMauro Carvalho Chehab if (readwrite == AF9005_CMD_WRITE) 98786baecfSMauro Carvalho Chehab for (i = 0; i < len; i++) 99c58b84eeSMauro Carvalho Chehab st->data[8 + i] = values[i]; 100786baecfSMauro Carvalho Chehab else if (type == AF9005_TUNER_REG) 101786baecfSMauro Carvalho Chehab /* read command for tuner, the first byte contains the i2c address */ 102c58b84eeSMauro Carvalho Chehab st->data[8] = values[0]; 103c58b84eeSMauro Carvalho Chehab st->data[7] = command; 104786baecfSMauro Carvalho Chehab 105c58b84eeSMauro Carvalho Chehab ret = dvb_usb_generic_rw(d, st->data, 16, st->data, 17, 0); 106786baecfSMauro Carvalho Chehab if (ret) 107c58b84eeSMauro Carvalho Chehab goto ret; 108786baecfSMauro Carvalho Chehab 109786baecfSMauro Carvalho Chehab /* sanity check */ 110c58b84eeSMauro Carvalho Chehab if (st->data[2] != AF9005_REGISTER_RW_ACK) { 111786baecfSMauro Carvalho Chehab err("generic read/write, wrong reply code."); 112c58b84eeSMauro Carvalho Chehab ret = -EIO; 113c58b84eeSMauro Carvalho Chehab goto ret; 114786baecfSMauro Carvalho Chehab } 115c58b84eeSMauro Carvalho Chehab if (st->data[3] != 0x0d) { 116786baecfSMauro Carvalho Chehab err("generic read/write, wrong length in reply."); 117c58b84eeSMauro Carvalho Chehab ret = -EIO; 118c58b84eeSMauro Carvalho Chehab goto ret; 119786baecfSMauro Carvalho Chehab } 120c58b84eeSMauro Carvalho Chehab if (st->data[4] != seq) { 121786baecfSMauro Carvalho Chehab err("generic read/write, wrong sequence in reply."); 122c58b84eeSMauro Carvalho Chehab ret = -EIO; 123c58b84eeSMauro Carvalho Chehab goto ret; 124786baecfSMauro Carvalho Chehab } 125786baecfSMauro Carvalho Chehab /* 126c58b84eeSMauro Carvalho Chehab * In thesis, both input and output buffers should have 127c58b84eeSMauro Carvalho Chehab * identical values for st->data[5] to st->data[8]. 128c58b84eeSMauro Carvalho Chehab * However, windows driver doesn't check these fields, in fact 129c58b84eeSMauro Carvalho Chehab * sometimes the register in the reply is different that what 130c58b84eeSMauro Carvalho Chehab * has been sent 131786baecfSMauro Carvalho Chehab */ 132c58b84eeSMauro Carvalho Chehab if (st->data[16] != 0x01) { 133786baecfSMauro Carvalho Chehab err("generic read/write wrong status code in reply."); 134c58b84eeSMauro Carvalho Chehab ret = -EIO; 135c58b84eeSMauro Carvalho Chehab goto ret; 136786baecfSMauro Carvalho Chehab } 137c58b84eeSMauro Carvalho Chehab 138786baecfSMauro Carvalho Chehab if (readwrite == AF9005_CMD_READ) 139786baecfSMauro Carvalho Chehab for (i = 0; i < len; i++) 140c58b84eeSMauro Carvalho Chehab values[i] = st->data[8 + i]; 141786baecfSMauro Carvalho Chehab 142c58b84eeSMauro Carvalho Chehab ret: 143c58b84eeSMauro Carvalho Chehab mutex_unlock(&st->data_mutex); 144c58b84eeSMauro Carvalho Chehab return ret; 145786baecfSMauro Carvalho Chehab 146786baecfSMauro Carvalho Chehab } 147786baecfSMauro Carvalho Chehab 148786baecfSMauro Carvalho Chehab int af9005_read_ofdm_register(struct dvb_usb_device *d, u16 reg, u8 * value) 149786baecfSMauro Carvalho Chehab { 150786baecfSMauro Carvalho Chehab int ret; 151786baecfSMauro Carvalho Chehab deb_reg("read register %x ", reg); 152786baecfSMauro Carvalho Chehab ret = af9005_generic_read_write(d, reg, 153786baecfSMauro Carvalho Chehab AF9005_CMD_READ, AF9005_OFDM_REG, 154786baecfSMauro Carvalho Chehab value, 1); 155786baecfSMauro Carvalho Chehab if (ret) 156786baecfSMauro Carvalho Chehab deb_reg("failed\n"); 157786baecfSMauro Carvalho Chehab else 158786baecfSMauro Carvalho Chehab deb_reg("value %x\n", *value); 159786baecfSMauro Carvalho Chehab return ret; 160786baecfSMauro Carvalho Chehab } 161786baecfSMauro Carvalho Chehab 162786baecfSMauro Carvalho Chehab int af9005_read_ofdm_registers(struct dvb_usb_device *d, u16 reg, 163786baecfSMauro Carvalho Chehab u8 * values, int len) 164786baecfSMauro Carvalho Chehab { 165786baecfSMauro Carvalho Chehab int ret; 166786baecfSMauro Carvalho Chehab deb_reg("read %d registers %x ", len, reg); 167786baecfSMauro Carvalho Chehab ret = af9005_generic_read_write(d, reg, 168786baecfSMauro Carvalho Chehab AF9005_CMD_READ, AF9005_OFDM_REG, 169786baecfSMauro Carvalho Chehab values, len); 170786baecfSMauro Carvalho Chehab if (ret) 171786baecfSMauro Carvalho Chehab deb_reg("failed\n"); 172786baecfSMauro Carvalho Chehab else 173786baecfSMauro Carvalho Chehab debug_dump(values, len, deb_reg); 174786baecfSMauro Carvalho Chehab return ret; 175786baecfSMauro Carvalho Chehab } 176786baecfSMauro Carvalho Chehab 177786baecfSMauro Carvalho Chehab int af9005_write_ofdm_register(struct dvb_usb_device *d, u16 reg, u8 value) 178786baecfSMauro Carvalho Chehab { 179786baecfSMauro Carvalho Chehab int ret; 180786baecfSMauro Carvalho Chehab u8 temp = value; 181786baecfSMauro Carvalho Chehab deb_reg("write register %x value %x ", reg, value); 182786baecfSMauro Carvalho Chehab ret = af9005_generic_read_write(d, reg, 183786baecfSMauro Carvalho Chehab AF9005_CMD_WRITE, AF9005_OFDM_REG, 184786baecfSMauro Carvalho Chehab &temp, 1); 185786baecfSMauro Carvalho Chehab if (ret) 186786baecfSMauro Carvalho Chehab deb_reg("failed\n"); 187786baecfSMauro Carvalho Chehab else 188786baecfSMauro Carvalho Chehab deb_reg("ok\n"); 189786baecfSMauro Carvalho Chehab return ret; 190786baecfSMauro Carvalho Chehab } 191786baecfSMauro Carvalho Chehab 192786baecfSMauro Carvalho Chehab int af9005_write_ofdm_registers(struct dvb_usb_device *d, u16 reg, 193786baecfSMauro Carvalho Chehab u8 * values, int len) 194786baecfSMauro Carvalho Chehab { 195786baecfSMauro Carvalho Chehab int ret; 196786baecfSMauro Carvalho Chehab deb_reg("write %d registers %x values ", len, reg); 197786baecfSMauro Carvalho Chehab debug_dump(values, len, deb_reg); 198786baecfSMauro Carvalho Chehab 199786baecfSMauro Carvalho Chehab ret = af9005_generic_read_write(d, reg, 200786baecfSMauro Carvalho Chehab AF9005_CMD_WRITE, AF9005_OFDM_REG, 201786baecfSMauro Carvalho Chehab values, len); 202786baecfSMauro Carvalho Chehab if (ret) 203786baecfSMauro Carvalho Chehab deb_reg("failed\n"); 204786baecfSMauro Carvalho Chehab else 205786baecfSMauro Carvalho Chehab deb_reg("ok\n"); 206786baecfSMauro Carvalho Chehab return ret; 207786baecfSMauro Carvalho Chehab } 208786baecfSMauro Carvalho Chehab 209786baecfSMauro Carvalho Chehab int af9005_read_register_bits(struct dvb_usb_device *d, u16 reg, u8 pos, 210786baecfSMauro Carvalho Chehab u8 len, u8 * value) 211786baecfSMauro Carvalho Chehab { 212786baecfSMauro Carvalho Chehab u8 temp; 213786baecfSMauro Carvalho Chehab int ret; 214786baecfSMauro Carvalho Chehab deb_reg("read bits %x %x %x", reg, pos, len); 215786baecfSMauro Carvalho Chehab ret = af9005_read_ofdm_register(d, reg, &temp); 216786baecfSMauro Carvalho Chehab if (ret) { 217786baecfSMauro Carvalho Chehab deb_reg(" failed\n"); 218786baecfSMauro Carvalho Chehab return ret; 219786baecfSMauro Carvalho Chehab } 220786baecfSMauro Carvalho Chehab *value = (temp >> pos) & regmask[len - 1]; 221786baecfSMauro Carvalho Chehab deb_reg(" value %x\n", *value); 222786baecfSMauro Carvalho Chehab return 0; 223786baecfSMauro Carvalho Chehab 224786baecfSMauro Carvalho Chehab } 225786baecfSMauro Carvalho Chehab 226786baecfSMauro Carvalho Chehab int af9005_write_register_bits(struct dvb_usb_device *d, u16 reg, u8 pos, 227786baecfSMauro Carvalho Chehab u8 len, u8 value) 228786baecfSMauro Carvalho Chehab { 229786baecfSMauro Carvalho Chehab u8 temp, mask; 230786baecfSMauro Carvalho Chehab int ret; 231786baecfSMauro Carvalho Chehab deb_reg("write bits %x %x %x value %x\n", reg, pos, len, value); 232786baecfSMauro Carvalho Chehab if (pos == 0 && len == 8) 233786baecfSMauro Carvalho Chehab return af9005_write_ofdm_register(d, reg, value); 234786baecfSMauro Carvalho Chehab ret = af9005_read_ofdm_register(d, reg, &temp); 235786baecfSMauro Carvalho Chehab if (ret) 236786baecfSMauro Carvalho Chehab return ret; 237786baecfSMauro Carvalho Chehab mask = regmask[len - 1] << pos; 238786baecfSMauro Carvalho Chehab temp = (temp & ~mask) | ((value << pos) & mask); 239786baecfSMauro Carvalho Chehab return af9005_write_ofdm_register(d, reg, temp); 240786baecfSMauro Carvalho Chehab 241786baecfSMauro Carvalho Chehab } 242786baecfSMauro Carvalho Chehab 243786baecfSMauro Carvalho Chehab static int af9005_usb_read_tuner_registers(struct dvb_usb_device *d, 244786baecfSMauro Carvalho Chehab u16 reg, u8 * values, int len) 245786baecfSMauro Carvalho Chehab { 246786baecfSMauro Carvalho Chehab return af9005_generic_read_write(d, reg, 247786baecfSMauro Carvalho Chehab AF9005_CMD_READ, AF9005_TUNER_REG, 248786baecfSMauro Carvalho Chehab values, len); 249786baecfSMauro Carvalho Chehab } 250786baecfSMauro Carvalho Chehab 251786baecfSMauro Carvalho Chehab static int af9005_usb_write_tuner_registers(struct dvb_usb_device *d, 252786baecfSMauro Carvalho Chehab u16 reg, u8 * values, int len) 253786baecfSMauro Carvalho Chehab { 254786baecfSMauro Carvalho Chehab return af9005_generic_read_write(d, reg, 255786baecfSMauro Carvalho Chehab AF9005_CMD_WRITE, 256786baecfSMauro Carvalho Chehab AF9005_TUNER_REG, values, len); 257786baecfSMauro Carvalho Chehab } 258786baecfSMauro Carvalho Chehab 259786baecfSMauro Carvalho Chehab int af9005_write_tuner_registers(struct dvb_usb_device *d, u16 reg, 260786baecfSMauro Carvalho Chehab u8 * values, int len) 261786baecfSMauro Carvalho Chehab { 262786baecfSMauro Carvalho Chehab /* don't let the name of this function mislead you: it's just used 263786baecfSMauro Carvalho Chehab as an interface from the firmware to the i2c bus. The actual 264786baecfSMauro Carvalho Chehab i2c addresses are contained in the data */ 265786baecfSMauro Carvalho Chehab int ret, i, done = 0, fail = 0; 266786baecfSMauro Carvalho Chehab u8 temp; 267786baecfSMauro Carvalho Chehab ret = af9005_usb_write_tuner_registers(d, reg, values, len); 268786baecfSMauro Carvalho Chehab if (ret) 269786baecfSMauro Carvalho Chehab return ret; 270786baecfSMauro Carvalho Chehab if (reg != 0xffff) { 271786baecfSMauro Carvalho Chehab /* check if write done (0xa40d bit 1) or fail (0xa40d bit 2) */ 272786baecfSMauro Carvalho Chehab for (i = 0; i < 200; i++) { 273786baecfSMauro Carvalho Chehab ret = 274786baecfSMauro Carvalho Chehab af9005_read_ofdm_register(d, 275786baecfSMauro Carvalho Chehab xd_I2C_i2c_m_status_wdat_done, 276786baecfSMauro Carvalho Chehab &temp); 277786baecfSMauro Carvalho Chehab if (ret) 278786baecfSMauro Carvalho Chehab return ret; 279786baecfSMauro Carvalho Chehab done = temp & (regmask[i2c_m_status_wdat_done_len - 1] 280786baecfSMauro Carvalho Chehab << i2c_m_status_wdat_done_pos); 281786baecfSMauro Carvalho Chehab if (done) 282786baecfSMauro Carvalho Chehab break; 283786baecfSMauro Carvalho Chehab fail = temp & (regmask[i2c_m_status_wdat_fail_len - 1] 284786baecfSMauro Carvalho Chehab << i2c_m_status_wdat_fail_pos); 285786baecfSMauro Carvalho Chehab if (fail) 286786baecfSMauro Carvalho Chehab break; 287786baecfSMauro Carvalho Chehab msleep(50); 288786baecfSMauro Carvalho Chehab } 289786baecfSMauro Carvalho Chehab if (i == 200) 290786baecfSMauro Carvalho Chehab return -ETIMEDOUT; 291786baecfSMauro Carvalho Chehab if (fail) { 292786baecfSMauro Carvalho Chehab /* clear write fail bit */ 293786baecfSMauro Carvalho Chehab af9005_write_register_bits(d, 294786baecfSMauro Carvalho Chehab xd_I2C_i2c_m_status_wdat_fail, 295786baecfSMauro Carvalho Chehab i2c_m_status_wdat_fail_pos, 296786baecfSMauro Carvalho Chehab i2c_m_status_wdat_fail_len, 297786baecfSMauro Carvalho Chehab 1); 298786baecfSMauro Carvalho Chehab return -EIO; 299786baecfSMauro Carvalho Chehab } 300786baecfSMauro Carvalho Chehab /* clear write done bit */ 301786baecfSMauro Carvalho Chehab ret = 302786baecfSMauro Carvalho Chehab af9005_write_register_bits(d, 303786baecfSMauro Carvalho Chehab xd_I2C_i2c_m_status_wdat_fail, 304786baecfSMauro Carvalho Chehab i2c_m_status_wdat_done_pos, 305786baecfSMauro Carvalho Chehab i2c_m_status_wdat_done_len, 1); 306786baecfSMauro Carvalho Chehab if (ret) 307786baecfSMauro Carvalho Chehab return ret; 308786baecfSMauro Carvalho Chehab } 309786baecfSMauro Carvalho Chehab return 0; 310786baecfSMauro Carvalho Chehab } 311786baecfSMauro Carvalho Chehab 312786baecfSMauro Carvalho Chehab int af9005_read_tuner_registers(struct dvb_usb_device *d, u16 reg, u8 addr, 313786baecfSMauro Carvalho Chehab u8 * values, int len) 314786baecfSMauro Carvalho Chehab { 315786baecfSMauro Carvalho Chehab /* don't let the name of this function mislead you: it's just used 316786baecfSMauro Carvalho Chehab as an interface from the firmware to the i2c bus. The actual 317786baecfSMauro Carvalho Chehab i2c addresses are contained in the data */ 318786baecfSMauro Carvalho Chehab int ret, i; 319786baecfSMauro Carvalho Chehab u8 temp, buf[2]; 320786baecfSMauro Carvalho Chehab 321786baecfSMauro Carvalho Chehab buf[0] = addr; /* tuner i2c address */ 322786baecfSMauro Carvalho Chehab buf[1] = values[0]; /* tuner register */ 323786baecfSMauro Carvalho Chehab 324786baecfSMauro Carvalho Chehab values[0] = addr + 0x01; /* i2c read address */ 325786baecfSMauro Carvalho Chehab 326786baecfSMauro Carvalho Chehab if (reg == APO_REG_I2C_RW_SILICON_TUNER) { 327786baecfSMauro Carvalho Chehab /* write tuner i2c address to tuner, 0c00c0 undocumented, found by sniffing */ 328786baecfSMauro Carvalho Chehab ret = af9005_write_tuner_registers(d, 0x00c0, buf, 2); 329786baecfSMauro Carvalho Chehab if (ret) 330786baecfSMauro Carvalho Chehab return ret; 331786baecfSMauro Carvalho Chehab } 332786baecfSMauro Carvalho Chehab 333786baecfSMauro Carvalho Chehab /* send read command to ofsm */ 334786baecfSMauro Carvalho Chehab ret = af9005_usb_read_tuner_registers(d, reg, values, 1); 335786baecfSMauro Carvalho Chehab if (ret) 336786baecfSMauro Carvalho Chehab return ret; 337786baecfSMauro Carvalho Chehab 338786baecfSMauro Carvalho Chehab /* check if read done */ 339786baecfSMauro Carvalho Chehab for (i = 0; i < 200; i++) { 340786baecfSMauro Carvalho Chehab ret = af9005_read_ofdm_register(d, 0xa408, &temp); 341786baecfSMauro Carvalho Chehab if (ret) 342786baecfSMauro Carvalho Chehab return ret; 343786baecfSMauro Carvalho Chehab if (temp & 0x01) 344786baecfSMauro Carvalho Chehab break; 345786baecfSMauro Carvalho Chehab msleep(50); 346786baecfSMauro Carvalho Chehab } 347786baecfSMauro Carvalho Chehab if (i == 200) 348786baecfSMauro Carvalho Chehab return -ETIMEDOUT; 349786baecfSMauro Carvalho Chehab 350786baecfSMauro Carvalho Chehab /* clear read done bit (by writing 1) */ 351786baecfSMauro Carvalho Chehab ret = af9005_write_ofdm_register(d, xd_I2C_i2c_m_data8, 1); 352786baecfSMauro Carvalho Chehab if (ret) 353786baecfSMauro Carvalho Chehab return ret; 354786baecfSMauro Carvalho Chehab 355786baecfSMauro Carvalho Chehab /* get read data (available from 0xa400) */ 356786baecfSMauro Carvalho Chehab for (i = 0; i < len; i++) { 357786baecfSMauro Carvalho Chehab ret = af9005_read_ofdm_register(d, 0xa400 + i, &temp); 358786baecfSMauro Carvalho Chehab if (ret) 359786baecfSMauro Carvalho Chehab return ret; 360786baecfSMauro Carvalho Chehab values[i] = temp; 361786baecfSMauro Carvalho Chehab } 362786baecfSMauro Carvalho Chehab return 0; 363786baecfSMauro Carvalho Chehab } 364786baecfSMauro Carvalho Chehab 365786baecfSMauro Carvalho Chehab static int af9005_i2c_write(struct dvb_usb_device *d, u8 i2caddr, u8 reg, 366786baecfSMauro Carvalho Chehab u8 * data, int len) 367786baecfSMauro Carvalho Chehab { 368786baecfSMauro Carvalho Chehab int ret, i; 369786baecfSMauro Carvalho Chehab u8 buf[3]; 370786baecfSMauro Carvalho Chehab deb_i2c("i2c_write i2caddr %x, reg %x, len %d data ", i2caddr, 371786baecfSMauro Carvalho Chehab reg, len); 372786baecfSMauro Carvalho Chehab debug_dump(data, len, deb_i2c); 373786baecfSMauro Carvalho Chehab 374786baecfSMauro Carvalho Chehab for (i = 0; i < len; i++) { 375786baecfSMauro Carvalho Chehab buf[0] = i2caddr; 376786baecfSMauro Carvalho Chehab buf[1] = reg + (u8) i; 377786baecfSMauro Carvalho Chehab buf[2] = data[i]; 378786baecfSMauro Carvalho Chehab ret = 379786baecfSMauro Carvalho Chehab af9005_write_tuner_registers(d, 380786baecfSMauro Carvalho Chehab APO_REG_I2C_RW_SILICON_TUNER, 381786baecfSMauro Carvalho Chehab buf, 3); 382786baecfSMauro Carvalho Chehab if (ret) { 383786baecfSMauro Carvalho Chehab deb_i2c("i2c_write failed\n"); 384786baecfSMauro Carvalho Chehab return ret; 385786baecfSMauro Carvalho Chehab } 386786baecfSMauro Carvalho Chehab } 387786baecfSMauro Carvalho Chehab deb_i2c("i2c_write ok\n"); 388786baecfSMauro Carvalho Chehab return 0; 389786baecfSMauro Carvalho Chehab } 390786baecfSMauro Carvalho Chehab 391786baecfSMauro Carvalho Chehab static int af9005_i2c_read(struct dvb_usb_device *d, u8 i2caddr, u8 reg, 392786baecfSMauro Carvalho Chehab u8 * data, int len) 393786baecfSMauro Carvalho Chehab { 394786baecfSMauro Carvalho Chehab int ret, i; 395786baecfSMauro Carvalho Chehab u8 temp; 396786baecfSMauro Carvalho Chehab deb_i2c("i2c_read i2caddr %x, reg %x, len %d\n ", i2caddr, reg, len); 397786baecfSMauro Carvalho Chehab for (i = 0; i < len; i++) { 398786baecfSMauro Carvalho Chehab temp = reg + i; 399786baecfSMauro Carvalho Chehab ret = 400786baecfSMauro Carvalho Chehab af9005_read_tuner_registers(d, 401786baecfSMauro Carvalho Chehab APO_REG_I2C_RW_SILICON_TUNER, 402786baecfSMauro Carvalho Chehab i2caddr, &temp, 1); 403786baecfSMauro Carvalho Chehab if (ret) { 404786baecfSMauro Carvalho Chehab deb_i2c("i2c_read failed\n"); 405786baecfSMauro Carvalho Chehab return ret; 406786baecfSMauro Carvalho Chehab } 407786baecfSMauro Carvalho Chehab data[i] = temp; 408786baecfSMauro Carvalho Chehab } 409786baecfSMauro Carvalho Chehab deb_i2c("i2c data read: "); 410786baecfSMauro Carvalho Chehab debug_dump(data, len, deb_i2c); 411786baecfSMauro Carvalho Chehab return 0; 412786baecfSMauro Carvalho Chehab } 413786baecfSMauro Carvalho Chehab 414786baecfSMauro Carvalho Chehab static int af9005_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], 415786baecfSMauro Carvalho Chehab int num) 416786baecfSMauro Carvalho Chehab { 417786baecfSMauro Carvalho Chehab /* only implements what the mt2060 module does, don't know how 418786baecfSMauro Carvalho Chehab to make it really generic */ 419786baecfSMauro Carvalho Chehab struct dvb_usb_device *d = i2c_get_adapdata(adap); 420786baecfSMauro Carvalho Chehab int ret; 421786baecfSMauro Carvalho Chehab u8 reg, addr; 422786baecfSMauro Carvalho Chehab u8 *value; 423786baecfSMauro Carvalho Chehab 424786baecfSMauro Carvalho Chehab if (mutex_lock_interruptible(&d->i2c_mutex) < 0) 425786baecfSMauro Carvalho Chehab return -EAGAIN; 426786baecfSMauro Carvalho Chehab 427786baecfSMauro Carvalho Chehab if (num > 2) 428786baecfSMauro Carvalho Chehab warn("more than 2 i2c messages at a time is not handled yet. TODO."); 429786baecfSMauro Carvalho Chehab 430786baecfSMauro Carvalho Chehab if (num == 2) { 431786baecfSMauro Carvalho Chehab /* reads a single register */ 432786baecfSMauro Carvalho Chehab reg = *msg[0].buf; 433786baecfSMauro Carvalho Chehab addr = msg[0].addr; 434786baecfSMauro Carvalho Chehab value = msg[1].buf; 435786baecfSMauro Carvalho Chehab ret = af9005_i2c_read(d, addr, reg, value, 1); 436786baecfSMauro Carvalho Chehab if (ret == 0) 437786baecfSMauro Carvalho Chehab ret = 2; 438786baecfSMauro Carvalho Chehab } else { 439786baecfSMauro Carvalho Chehab /* write one or more registers */ 440786baecfSMauro Carvalho Chehab reg = msg[0].buf[0]; 441786baecfSMauro Carvalho Chehab addr = msg[0].addr; 442786baecfSMauro Carvalho Chehab value = &msg[0].buf[1]; 443786baecfSMauro Carvalho Chehab ret = af9005_i2c_write(d, addr, reg, value, msg[0].len - 1); 444786baecfSMauro Carvalho Chehab if (ret == 0) 445786baecfSMauro Carvalho Chehab ret = 1; 446786baecfSMauro Carvalho Chehab } 447786baecfSMauro Carvalho Chehab 448786baecfSMauro Carvalho Chehab mutex_unlock(&d->i2c_mutex); 449786baecfSMauro Carvalho Chehab return ret; 450786baecfSMauro Carvalho Chehab } 451786baecfSMauro Carvalho Chehab 452786baecfSMauro Carvalho Chehab static u32 af9005_i2c_func(struct i2c_adapter *adapter) 453786baecfSMauro Carvalho Chehab { 454786baecfSMauro Carvalho Chehab return I2C_FUNC_I2C; 455786baecfSMauro Carvalho Chehab } 456786baecfSMauro Carvalho Chehab 457786baecfSMauro Carvalho Chehab static struct i2c_algorithm af9005_i2c_algo = { 458786baecfSMauro Carvalho Chehab .master_xfer = af9005_i2c_xfer, 459786baecfSMauro Carvalho Chehab .functionality = af9005_i2c_func, 460786baecfSMauro Carvalho Chehab }; 461786baecfSMauro Carvalho Chehab 462786baecfSMauro Carvalho Chehab int af9005_send_command(struct dvb_usb_device *d, u8 command, u8 * wbuf, 463786baecfSMauro Carvalho Chehab int wlen, u8 * rbuf, int rlen) 464786baecfSMauro Carvalho Chehab { 465786baecfSMauro Carvalho Chehab struct af9005_device_state *st = d->priv; 466786baecfSMauro Carvalho Chehab 467786baecfSMauro Carvalho Chehab int ret, i, packet_len; 468c58b84eeSMauro Carvalho Chehab u8 seq; 469786baecfSMauro Carvalho Chehab 470786baecfSMauro Carvalho Chehab if (wlen < 0) { 471786baecfSMauro Carvalho Chehab err("send command, wlen less than 0 bytes. Makes no sense."); 472786baecfSMauro Carvalho Chehab return -EINVAL; 473786baecfSMauro Carvalho Chehab } 474786baecfSMauro Carvalho Chehab if (wlen > 54) { 475786baecfSMauro Carvalho Chehab err("send command, wlen more than 54 bytes. Not supported."); 476786baecfSMauro Carvalho Chehab return -EINVAL; 477786baecfSMauro Carvalho Chehab } 478786baecfSMauro Carvalho Chehab if (rlen > 54) { 479786baecfSMauro Carvalho Chehab err("send command, rlen more than 54 bytes. Not supported."); 480786baecfSMauro Carvalho Chehab return -EINVAL; 481786baecfSMauro Carvalho Chehab } 482786baecfSMauro Carvalho Chehab packet_len = wlen + 5; 483786baecfSMauro Carvalho Chehab 484c58b84eeSMauro Carvalho Chehab mutex_lock(&st->data_mutex); 485c58b84eeSMauro Carvalho Chehab 486c58b84eeSMauro Carvalho Chehab st->data[0] = (u8) (packet_len & 0xff); 487c58b84eeSMauro Carvalho Chehab st->data[1] = (u8) ((packet_len & 0xff00) >> 8); 488c58b84eeSMauro Carvalho Chehab 489c58b84eeSMauro Carvalho Chehab st->data[2] = 0x26; /* packet type */ 490c58b84eeSMauro Carvalho Chehab st->data[3] = wlen + 3; 491c58b84eeSMauro Carvalho Chehab st->data[4] = seq = st->sequence++; 492c58b84eeSMauro Carvalho Chehab st->data[5] = command; 493c58b84eeSMauro Carvalho Chehab st->data[6] = wlen; 494786baecfSMauro Carvalho Chehab for (i = 0; i < wlen; i++) 495c58b84eeSMauro Carvalho Chehab st->data[7 + i] = wbuf[i]; 496c58b84eeSMauro Carvalho Chehab ret = dvb_usb_generic_rw(d, st->data, wlen + 7, st->data, rlen + 7, 0); 497c58b84eeSMauro Carvalho Chehab if (st->data[2] != 0x27) { 498786baecfSMauro Carvalho Chehab err("send command, wrong reply code."); 499c58b84eeSMauro Carvalho Chehab ret = -EIO; 500c58b84eeSMauro Carvalho Chehab } else if (st->data[4] != seq) { 501786baecfSMauro Carvalho Chehab err("send command, wrong sequence in reply."); 502c58b84eeSMauro Carvalho Chehab ret = -EIO; 503c58b84eeSMauro Carvalho Chehab } else if (st->data[5] != 0x01) { 504786baecfSMauro Carvalho Chehab err("send command, wrong status code in reply."); 505c58b84eeSMauro Carvalho Chehab ret = -EIO; 506c58b84eeSMauro Carvalho Chehab } else if (st->data[6] != rlen) { 507786baecfSMauro Carvalho Chehab err("send command, invalid data length in reply."); 508c58b84eeSMauro Carvalho Chehab ret = -EIO; 509786baecfSMauro Carvalho Chehab } 510c58b84eeSMauro Carvalho Chehab if (!ret) { 511786baecfSMauro Carvalho Chehab for (i = 0; i < rlen; i++) 512c58b84eeSMauro Carvalho Chehab rbuf[i] = st->data[i + 7]; 513c58b84eeSMauro Carvalho Chehab } 514c58b84eeSMauro Carvalho Chehab 515c58b84eeSMauro Carvalho Chehab mutex_unlock(&st->data_mutex); 516c58b84eeSMauro Carvalho Chehab return ret; 517786baecfSMauro Carvalho Chehab } 518786baecfSMauro Carvalho Chehab 519786baecfSMauro Carvalho Chehab int af9005_read_eeprom(struct dvb_usb_device *d, u8 address, u8 * values, 520786baecfSMauro Carvalho Chehab int len) 521786baecfSMauro Carvalho Chehab { 522786baecfSMauro Carvalho Chehab struct af9005_device_state *st = d->priv; 523c58b84eeSMauro Carvalho Chehab u8 seq; 524786baecfSMauro Carvalho Chehab int ret, i; 525786baecfSMauro Carvalho Chehab 526c58b84eeSMauro Carvalho Chehab mutex_lock(&st->data_mutex); 527786baecfSMauro Carvalho Chehab 528c58b84eeSMauro Carvalho Chehab memset(st->data, 0, sizeof(st->data)); 529786baecfSMauro Carvalho Chehab 530c58b84eeSMauro Carvalho Chehab st->data[0] = 14; /* length of rest of packet low */ 531c58b84eeSMauro Carvalho Chehab st->data[1] = 0; /* length of rest of packer high */ 532786baecfSMauro Carvalho Chehab 533c58b84eeSMauro Carvalho Chehab st->data[2] = 0x2a; /* read/write eeprom */ 534786baecfSMauro Carvalho Chehab 535c58b84eeSMauro Carvalho Chehab st->data[3] = 12; /* size */ 536786baecfSMauro Carvalho Chehab 537c58b84eeSMauro Carvalho Chehab st->data[4] = seq = st->sequence++; 538786baecfSMauro Carvalho Chehab 539c58b84eeSMauro Carvalho Chehab st->data[5] = 0; /* read */ 540c58b84eeSMauro Carvalho Chehab 541c58b84eeSMauro Carvalho Chehab st->data[6] = len; 542c58b84eeSMauro Carvalho Chehab st->data[7] = address; 543c58b84eeSMauro Carvalho Chehab ret = dvb_usb_generic_rw(d, st->data, 16, st->data, 14, 0); 544c58b84eeSMauro Carvalho Chehab if (st->data[2] != 0x2b) { 545786baecfSMauro Carvalho Chehab err("Read eeprom, invalid reply code"); 546c58b84eeSMauro Carvalho Chehab ret = -EIO; 547c58b84eeSMauro Carvalho Chehab } else if (st->data[3] != 10) { 548786baecfSMauro Carvalho Chehab err("Read eeprom, invalid reply length"); 549c58b84eeSMauro Carvalho Chehab ret = -EIO; 550c58b84eeSMauro Carvalho Chehab } else if (st->data[4] != seq) { 551786baecfSMauro Carvalho Chehab err("Read eeprom, wrong sequence in reply "); 552c58b84eeSMauro Carvalho Chehab ret = -EIO; 553c58b84eeSMauro Carvalho Chehab } else if (st->data[5] != 1) { 554786baecfSMauro Carvalho Chehab err("Read eeprom, wrong status in reply "); 555c58b84eeSMauro Carvalho Chehab ret = -EIO; 556786baecfSMauro Carvalho Chehab } 557786baecfSMauro Carvalho Chehab 558c58b84eeSMauro Carvalho Chehab if (!ret) { 559c58b84eeSMauro Carvalho Chehab for (i = 0; i < len; i++) 560c58b84eeSMauro Carvalho Chehab values[i] = st->data[6 + i]; 561c58b84eeSMauro Carvalho Chehab } 562c58b84eeSMauro Carvalho Chehab mutex_unlock(&st->data_mutex); 563c58b84eeSMauro Carvalho Chehab 564c58b84eeSMauro Carvalho Chehab return ret; 565c58b84eeSMauro Carvalho Chehab } 566c58b84eeSMauro Carvalho Chehab 567c58b84eeSMauro Carvalho Chehab static int af9005_boot_packet(struct usb_device *udev, int type, u8 *reply, 568c58b84eeSMauro Carvalho Chehab u8 *buf, int size) 569786baecfSMauro Carvalho Chehab { 570786baecfSMauro Carvalho Chehab u16 checksum; 571786baecfSMauro Carvalho Chehab int act_len, i, ret; 572c58b84eeSMauro Carvalho Chehab 573c58b84eeSMauro Carvalho Chehab memset(buf, 0, size); 574786baecfSMauro Carvalho Chehab buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff); 575786baecfSMauro Carvalho Chehab buf[1] = (u8) ((FW_BULKOUT_SIZE >> 8) & 0xff); 576786baecfSMauro Carvalho Chehab switch (type) { 577786baecfSMauro Carvalho Chehab case FW_CONFIG: 578786baecfSMauro Carvalho Chehab buf[2] = 0x11; 579786baecfSMauro Carvalho Chehab buf[3] = 0x04; 580786baecfSMauro Carvalho Chehab buf[4] = 0x00; /* sequence number, original driver doesn't increment it here */ 581786baecfSMauro Carvalho Chehab buf[5] = 0x03; 582786baecfSMauro Carvalho Chehab checksum = buf[4] + buf[5]; 583786baecfSMauro Carvalho Chehab buf[6] = (u8) ((checksum >> 8) & 0xff); 584786baecfSMauro Carvalho Chehab buf[7] = (u8) (checksum & 0xff); 585786baecfSMauro Carvalho Chehab break; 586786baecfSMauro Carvalho Chehab case FW_CONFIRM: 587786baecfSMauro Carvalho Chehab buf[2] = 0x11; 588786baecfSMauro Carvalho Chehab buf[3] = 0x04; 589786baecfSMauro Carvalho Chehab buf[4] = 0x00; /* sequence number, original driver doesn't increment it here */ 590786baecfSMauro Carvalho Chehab buf[5] = 0x01; 591786baecfSMauro Carvalho Chehab checksum = buf[4] + buf[5]; 592786baecfSMauro Carvalho Chehab buf[6] = (u8) ((checksum >> 8) & 0xff); 593786baecfSMauro Carvalho Chehab buf[7] = (u8) (checksum & 0xff); 594786baecfSMauro Carvalho Chehab break; 595786baecfSMauro Carvalho Chehab case FW_BOOT: 596786baecfSMauro Carvalho Chehab buf[2] = 0x10; 597786baecfSMauro Carvalho Chehab buf[3] = 0x08; 598786baecfSMauro Carvalho Chehab buf[4] = 0x00; /* sequence number, original driver doesn't increment it here */ 599786baecfSMauro Carvalho Chehab buf[5] = 0x97; 600786baecfSMauro Carvalho Chehab buf[6] = 0xaa; 601786baecfSMauro Carvalho Chehab buf[7] = 0x55; 602786baecfSMauro Carvalho Chehab buf[8] = 0xa5; 603786baecfSMauro Carvalho Chehab buf[9] = 0x5a; 604786baecfSMauro Carvalho Chehab checksum = 0; 605786baecfSMauro Carvalho Chehab for (i = 4; i <= 9; i++) 606786baecfSMauro Carvalho Chehab checksum += buf[i]; 607786baecfSMauro Carvalho Chehab buf[10] = (u8) ((checksum >> 8) & 0xff); 608786baecfSMauro Carvalho Chehab buf[11] = (u8) (checksum & 0xff); 609786baecfSMauro Carvalho Chehab break; 610786baecfSMauro Carvalho Chehab default: 611786baecfSMauro Carvalho Chehab err("boot packet invalid boot packet type"); 612786baecfSMauro Carvalho Chehab return -EINVAL; 613786baecfSMauro Carvalho Chehab } 614786baecfSMauro Carvalho Chehab deb_fw(">>> "); 615786baecfSMauro Carvalho Chehab debug_dump(buf, FW_BULKOUT_SIZE + 2, deb_fw); 616786baecfSMauro Carvalho Chehab 617786baecfSMauro Carvalho Chehab ret = usb_bulk_msg(udev, 618786baecfSMauro Carvalho Chehab usb_sndbulkpipe(udev, 0x02), 619786baecfSMauro Carvalho Chehab buf, FW_BULKOUT_SIZE + 2, &act_len, 2000); 620786baecfSMauro Carvalho Chehab if (ret) 621786baecfSMauro Carvalho Chehab err("boot packet bulk message failed: %d (%d/%d)", ret, 622786baecfSMauro Carvalho Chehab FW_BULKOUT_SIZE + 2, act_len); 623786baecfSMauro Carvalho Chehab else 624786baecfSMauro Carvalho Chehab ret = act_len != FW_BULKOUT_SIZE + 2 ? -1 : 0; 625786baecfSMauro Carvalho Chehab if (ret) 626786baecfSMauro Carvalho Chehab return ret; 627786baecfSMauro Carvalho Chehab memset(buf, 0, 9); 628786baecfSMauro Carvalho Chehab ret = usb_bulk_msg(udev, 629786baecfSMauro Carvalho Chehab usb_rcvbulkpipe(udev, 0x01), buf, 9, &act_len, 2000); 630786baecfSMauro Carvalho Chehab if (ret) { 631786baecfSMauro Carvalho Chehab err("boot packet recv bulk message failed: %d", ret); 632786baecfSMauro Carvalho Chehab return ret; 633786baecfSMauro Carvalho Chehab } 634786baecfSMauro Carvalho Chehab deb_fw("<<< "); 635786baecfSMauro Carvalho Chehab debug_dump(buf, act_len, deb_fw); 636786baecfSMauro Carvalho Chehab checksum = 0; 637786baecfSMauro Carvalho Chehab switch (type) { 638786baecfSMauro Carvalho Chehab case FW_CONFIG: 639786baecfSMauro Carvalho Chehab if (buf[2] != 0x11) { 640786baecfSMauro Carvalho Chehab err("boot bad config header."); 641786baecfSMauro Carvalho Chehab return -EIO; 642786baecfSMauro Carvalho Chehab } 643786baecfSMauro Carvalho Chehab if (buf[3] != 0x05) { 644786baecfSMauro Carvalho Chehab err("boot bad config size."); 645786baecfSMauro Carvalho Chehab return -EIO; 646786baecfSMauro Carvalho Chehab } 647786baecfSMauro Carvalho Chehab if (buf[4] != 0x00) { 648786baecfSMauro Carvalho Chehab err("boot bad config sequence."); 649786baecfSMauro Carvalho Chehab return -EIO; 650786baecfSMauro Carvalho Chehab } 651786baecfSMauro Carvalho Chehab if (buf[5] != 0x04) { 652786baecfSMauro Carvalho Chehab err("boot bad config subtype."); 653786baecfSMauro Carvalho Chehab return -EIO; 654786baecfSMauro Carvalho Chehab } 655786baecfSMauro Carvalho Chehab for (i = 4; i <= 6; i++) 656786baecfSMauro Carvalho Chehab checksum += buf[i]; 657786baecfSMauro Carvalho Chehab if (buf[7] * 256 + buf[8] != checksum) { 658786baecfSMauro Carvalho Chehab err("boot bad config checksum."); 659786baecfSMauro Carvalho Chehab return -EIO; 660786baecfSMauro Carvalho Chehab } 661786baecfSMauro Carvalho Chehab *reply = buf[6]; 662786baecfSMauro Carvalho Chehab break; 663786baecfSMauro Carvalho Chehab case FW_CONFIRM: 664786baecfSMauro Carvalho Chehab if (buf[2] != 0x11) { 665786baecfSMauro Carvalho Chehab err("boot bad confirm header."); 666786baecfSMauro Carvalho Chehab return -EIO; 667786baecfSMauro Carvalho Chehab } 668786baecfSMauro Carvalho Chehab if (buf[3] != 0x05) { 669786baecfSMauro Carvalho Chehab err("boot bad confirm size."); 670786baecfSMauro Carvalho Chehab return -EIO; 671786baecfSMauro Carvalho Chehab } 672786baecfSMauro Carvalho Chehab if (buf[4] != 0x00) { 673786baecfSMauro Carvalho Chehab err("boot bad confirm sequence."); 674786baecfSMauro Carvalho Chehab return -EIO; 675786baecfSMauro Carvalho Chehab } 676786baecfSMauro Carvalho Chehab if (buf[5] != 0x02) { 677786baecfSMauro Carvalho Chehab err("boot bad confirm subtype."); 678786baecfSMauro Carvalho Chehab return -EIO; 679786baecfSMauro Carvalho Chehab } 680786baecfSMauro Carvalho Chehab for (i = 4; i <= 6; i++) 681786baecfSMauro Carvalho Chehab checksum += buf[i]; 682786baecfSMauro Carvalho Chehab if (buf[7] * 256 + buf[8] != checksum) { 683786baecfSMauro Carvalho Chehab err("boot bad confirm checksum."); 684786baecfSMauro Carvalho Chehab return -EIO; 685786baecfSMauro Carvalho Chehab } 686786baecfSMauro Carvalho Chehab *reply = buf[6]; 687786baecfSMauro Carvalho Chehab break; 688786baecfSMauro Carvalho Chehab case FW_BOOT: 689786baecfSMauro Carvalho Chehab if (buf[2] != 0x10) { 690786baecfSMauro Carvalho Chehab err("boot bad boot header."); 691786baecfSMauro Carvalho Chehab return -EIO; 692786baecfSMauro Carvalho Chehab } 693786baecfSMauro Carvalho Chehab if (buf[3] != 0x05) { 694786baecfSMauro Carvalho Chehab err("boot bad boot size."); 695786baecfSMauro Carvalho Chehab return -EIO; 696786baecfSMauro Carvalho Chehab } 697786baecfSMauro Carvalho Chehab if (buf[4] != 0x00) { 698786baecfSMauro Carvalho Chehab err("boot bad boot sequence."); 699786baecfSMauro Carvalho Chehab return -EIO; 700786baecfSMauro Carvalho Chehab } 701786baecfSMauro Carvalho Chehab if (buf[5] != 0x01) { 702786baecfSMauro Carvalho Chehab err("boot bad boot pattern 01."); 703786baecfSMauro Carvalho Chehab return -EIO; 704786baecfSMauro Carvalho Chehab } 705786baecfSMauro Carvalho Chehab if (buf[6] != 0x10) { 706786baecfSMauro Carvalho Chehab err("boot bad boot pattern 10."); 707786baecfSMauro Carvalho Chehab return -EIO; 708786baecfSMauro Carvalho Chehab } 709786baecfSMauro Carvalho Chehab for (i = 4; i <= 6; i++) 710786baecfSMauro Carvalho Chehab checksum += buf[i]; 711786baecfSMauro Carvalho Chehab if (buf[7] * 256 + buf[8] != checksum) { 712786baecfSMauro Carvalho Chehab err("boot bad boot checksum."); 713786baecfSMauro Carvalho Chehab return -EIO; 714786baecfSMauro Carvalho Chehab } 715786baecfSMauro Carvalho Chehab break; 716786baecfSMauro Carvalho Chehab 717786baecfSMauro Carvalho Chehab } 718786baecfSMauro Carvalho Chehab 719786baecfSMauro Carvalho Chehab return 0; 720786baecfSMauro Carvalho Chehab } 721786baecfSMauro Carvalho Chehab 722786baecfSMauro Carvalho Chehab static int af9005_download_firmware(struct usb_device *udev, const struct firmware *fw) 723786baecfSMauro Carvalho Chehab { 724786baecfSMauro Carvalho Chehab int i, packets, ret, act_len; 725786baecfSMauro Carvalho Chehab 726c58b84eeSMauro Carvalho Chehab u8 *buf; 727786baecfSMauro Carvalho Chehab u8 reply; 728786baecfSMauro Carvalho Chehab 729c58b84eeSMauro Carvalho Chehab buf = kmalloc(FW_BULKOUT_SIZE + 2, GFP_KERNEL); 730c58b84eeSMauro Carvalho Chehab if (!buf) 731c58b84eeSMauro Carvalho Chehab return -ENOMEM; 732c58b84eeSMauro Carvalho Chehab 733c58b84eeSMauro Carvalho Chehab ret = af9005_boot_packet(udev, FW_CONFIG, &reply, buf, 734c58b84eeSMauro Carvalho Chehab FW_BULKOUT_SIZE + 2); 735786baecfSMauro Carvalho Chehab if (ret) 736c58b84eeSMauro Carvalho Chehab goto err; 737786baecfSMauro Carvalho Chehab if (reply != 0x01) { 738786baecfSMauro Carvalho Chehab err("before downloading firmware, FW_CONFIG expected 0x01, received 0x%x", reply); 739c58b84eeSMauro Carvalho Chehab ret = -EIO; 740c58b84eeSMauro Carvalho Chehab goto err; 741786baecfSMauro Carvalho Chehab } 742786baecfSMauro Carvalho Chehab packets = fw->size / FW_BULKOUT_SIZE; 743786baecfSMauro Carvalho Chehab buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff); 744786baecfSMauro Carvalho Chehab buf[1] = (u8) ((FW_BULKOUT_SIZE >> 8) & 0xff); 745786baecfSMauro Carvalho Chehab for (i = 0; i < packets; i++) { 746786baecfSMauro Carvalho Chehab memcpy(&buf[2], fw->data + i * FW_BULKOUT_SIZE, 747786baecfSMauro Carvalho Chehab FW_BULKOUT_SIZE); 748786baecfSMauro Carvalho Chehab deb_fw(">>> "); 749786baecfSMauro Carvalho Chehab debug_dump(buf, FW_BULKOUT_SIZE + 2, deb_fw); 750786baecfSMauro Carvalho Chehab ret = usb_bulk_msg(udev, 751786baecfSMauro Carvalho Chehab usb_sndbulkpipe(udev, 0x02), 752786baecfSMauro Carvalho Chehab buf, FW_BULKOUT_SIZE + 2, &act_len, 1000); 753786baecfSMauro Carvalho Chehab if (ret) { 754786baecfSMauro Carvalho Chehab err("firmware download failed at packet %d with code %d", i, ret); 755c58b84eeSMauro Carvalho Chehab goto err; 756786baecfSMauro Carvalho Chehab } 757786baecfSMauro Carvalho Chehab } 758c58b84eeSMauro Carvalho Chehab ret = af9005_boot_packet(udev, FW_CONFIRM, &reply, 759c58b84eeSMauro Carvalho Chehab buf, FW_BULKOUT_SIZE + 2); 760786baecfSMauro Carvalho Chehab if (ret) 761c58b84eeSMauro Carvalho Chehab goto err; 762786baecfSMauro Carvalho Chehab if (reply != (u8) (packets & 0xff)) { 763786baecfSMauro Carvalho Chehab err("after downloading firmware, FW_CONFIRM expected 0x%x, received 0x%x", packets & 0xff, reply); 764c58b84eeSMauro Carvalho Chehab ret = -EIO; 765c58b84eeSMauro Carvalho Chehab goto err; 766786baecfSMauro Carvalho Chehab } 767c58b84eeSMauro Carvalho Chehab ret = af9005_boot_packet(udev, FW_BOOT, &reply, buf, 768c58b84eeSMauro Carvalho Chehab FW_BULKOUT_SIZE + 2); 769786baecfSMauro Carvalho Chehab if (ret) 770c58b84eeSMauro Carvalho Chehab goto err; 771c58b84eeSMauro Carvalho Chehab ret = af9005_boot_packet(udev, FW_CONFIG, &reply, buf, 772c58b84eeSMauro Carvalho Chehab FW_BULKOUT_SIZE + 2); 773786baecfSMauro Carvalho Chehab if (ret) 774c58b84eeSMauro Carvalho Chehab goto err; 775786baecfSMauro Carvalho Chehab if (reply != 0x02) { 776786baecfSMauro Carvalho Chehab err("after downloading firmware, FW_CONFIG expected 0x02, received 0x%x", reply); 777c58b84eeSMauro Carvalho Chehab ret = -EIO; 778c58b84eeSMauro Carvalho Chehab goto err; 779786baecfSMauro Carvalho Chehab } 780786baecfSMauro Carvalho Chehab 781c58b84eeSMauro Carvalho Chehab err: 782c58b84eeSMauro Carvalho Chehab kfree(buf); 783c58b84eeSMauro Carvalho Chehab return ret; 784786baecfSMauro Carvalho Chehab 785786baecfSMauro Carvalho Chehab } 786786baecfSMauro Carvalho Chehab 787786baecfSMauro Carvalho Chehab int af9005_led_control(struct dvb_usb_device *d, int onoff) 788786baecfSMauro Carvalho Chehab { 789786baecfSMauro Carvalho Chehab struct af9005_device_state *st = d->priv; 790786baecfSMauro Carvalho Chehab int temp, ret; 791786baecfSMauro Carvalho Chehab 792786baecfSMauro Carvalho Chehab if (onoff && dvb_usb_af9005_led) 793786baecfSMauro Carvalho Chehab temp = 1; 794786baecfSMauro Carvalho Chehab else 795786baecfSMauro Carvalho Chehab temp = 0; 796786baecfSMauro Carvalho Chehab if (st->led_state != temp) { 797786baecfSMauro Carvalho Chehab ret = 798786baecfSMauro Carvalho Chehab af9005_write_register_bits(d, xd_p_reg_top_locken1, 799786baecfSMauro Carvalho Chehab reg_top_locken1_pos, 800786baecfSMauro Carvalho Chehab reg_top_locken1_len, temp); 801786baecfSMauro Carvalho Chehab if (ret) 802786baecfSMauro Carvalho Chehab return ret; 803786baecfSMauro Carvalho Chehab ret = 804786baecfSMauro Carvalho Chehab af9005_write_register_bits(d, xd_p_reg_top_lock1, 805786baecfSMauro Carvalho Chehab reg_top_lock1_pos, 806786baecfSMauro Carvalho Chehab reg_top_lock1_len, temp); 807786baecfSMauro Carvalho Chehab if (ret) 808786baecfSMauro Carvalho Chehab return ret; 809786baecfSMauro Carvalho Chehab st->led_state = temp; 810786baecfSMauro Carvalho Chehab } 811786baecfSMauro Carvalho Chehab return 0; 812786baecfSMauro Carvalho Chehab } 813786baecfSMauro Carvalho Chehab 814786baecfSMauro Carvalho Chehab static int af9005_frontend_attach(struct dvb_usb_adapter *adap) 815786baecfSMauro Carvalho Chehab { 816786baecfSMauro Carvalho Chehab u8 buf[8]; 817786baecfSMauro Carvalho Chehab int i; 818786baecfSMauro Carvalho Chehab 819786baecfSMauro Carvalho Chehab /* without these calls the first commands after downloading 820786baecfSMauro Carvalho Chehab the firmware fail. I put these calls here to simulate 821786baecfSMauro Carvalho Chehab what it is done in dvb-usb-init.c. 822786baecfSMauro Carvalho Chehab */ 823786baecfSMauro Carvalho Chehab struct usb_device *udev = adap->dev->udev; 824786baecfSMauro Carvalho Chehab usb_clear_halt(udev, usb_sndbulkpipe(udev, 2)); 825786baecfSMauro Carvalho Chehab usb_clear_halt(udev, usb_rcvbulkpipe(udev, 1)); 826786baecfSMauro Carvalho Chehab if (dvb_usb_af9005_dump_eeprom) { 827786baecfSMauro Carvalho Chehab printk("EEPROM DUMP\n"); 828786baecfSMauro Carvalho Chehab for (i = 0; i < 255; i += 8) { 829786baecfSMauro Carvalho Chehab af9005_read_eeprom(adap->dev, i, buf, 8); 830786baecfSMauro Carvalho Chehab printk("ADDR %x ", i); 831786baecfSMauro Carvalho Chehab debug_dump(buf, 8, printk); 832786baecfSMauro Carvalho Chehab } 833786baecfSMauro Carvalho Chehab } 834786baecfSMauro Carvalho Chehab adap->fe_adap[0].fe = af9005_fe_attach(adap->dev); 835786baecfSMauro Carvalho Chehab return 0; 836786baecfSMauro Carvalho Chehab } 837786baecfSMauro Carvalho Chehab 838786baecfSMauro Carvalho Chehab static int af9005_rc_query(struct dvb_usb_device *d, u32 * event, int *state) 839786baecfSMauro Carvalho Chehab { 840786baecfSMauro Carvalho Chehab struct af9005_device_state *st = d->priv; 841786baecfSMauro Carvalho Chehab int ret, len; 842c58b84eeSMauro Carvalho Chehab u8 seq; 843786baecfSMauro Carvalho Chehab 844786baecfSMauro Carvalho Chehab *state = REMOTE_NO_KEY_PRESSED; 845786baecfSMauro Carvalho Chehab if (rc_decode == NULL) { 846786baecfSMauro Carvalho Chehab /* it shouldn't never come here */ 847786baecfSMauro Carvalho Chehab return 0; 848786baecfSMauro Carvalho Chehab } 849c58b84eeSMauro Carvalho Chehab 850c58b84eeSMauro Carvalho Chehab mutex_lock(&st->data_mutex); 851c58b84eeSMauro Carvalho Chehab 852786baecfSMauro Carvalho Chehab /* deb_info("rc_query\n"); */ 853c58b84eeSMauro Carvalho Chehab st->data[0] = 3; /* rest of packet length low */ 854c58b84eeSMauro Carvalho Chehab st->data[1] = 0; /* rest of packet lentgh high */ 855c58b84eeSMauro Carvalho Chehab st->data[2] = 0x40; /* read remote */ 856c58b84eeSMauro Carvalho Chehab st->data[3] = 1; /* rest of packet length */ 857c58b84eeSMauro Carvalho Chehab st->data[4] = seq = st->sequence++; /* sequence number */ 858c58b84eeSMauro Carvalho Chehab ret = dvb_usb_generic_rw(d, st->data, 5, st->data, 256, 0); 859786baecfSMauro Carvalho Chehab if (ret) { 860786baecfSMauro Carvalho Chehab err("rc query failed"); 861c58b84eeSMauro Carvalho Chehab goto ret; 862786baecfSMauro Carvalho Chehab } 863c58b84eeSMauro Carvalho Chehab if (st->data[2] != 0x41) { 864786baecfSMauro Carvalho Chehab err("rc query bad header."); 865c58b84eeSMauro Carvalho Chehab ret = -EIO; 866c58b84eeSMauro Carvalho Chehab goto ret; 867c58b84eeSMauro Carvalho Chehab } else if (st->data[4] != seq) { 868786baecfSMauro Carvalho Chehab err("rc query bad sequence."); 869c58b84eeSMauro Carvalho Chehab ret = -EIO; 870c58b84eeSMauro Carvalho Chehab goto ret; 871786baecfSMauro Carvalho Chehab } 872c58b84eeSMauro Carvalho Chehab len = st->data[5]; 873786baecfSMauro Carvalho Chehab if (len > 246) { 874786baecfSMauro Carvalho Chehab err("rc query invalid length"); 875c58b84eeSMauro Carvalho Chehab ret = -EIO; 876c58b84eeSMauro Carvalho Chehab goto ret; 877786baecfSMauro Carvalho Chehab } 878786baecfSMauro Carvalho Chehab if (len > 0) { 879786baecfSMauro Carvalho Chehab deb_rc("rc data (%d) ", len); 880c58b84eeSMauro Carvalho Chehab debug_dump((st->data + 6), len, deb_rc); 881c58b84eeSMauro Carvalho Chehab ret = rc_decode(d, &st->data[6], len, event, state); 882786baecfSMauro Carvalho Chehab if (ret) { 883786baecfSMauro Carvalho Chehab err("rc_decode failed"); 884c58b84eeSMauro Carvalho Chehab goto ret; 885786baecfSMauro Carvalho Chehab } else { 886786baecfSMauro Carvalho Chehab deb_rc("rc_decode state %x event %x\n", *state, *event); 887786baecfSMauro Carvalho Chehab if (*state == REMOTE_KEY_REPEAT) 888786baecfSMauro Carvalho Chehab *event = d->last_event; 889786baecfSMauro Carvalho Chehab } 890786baecfSMauro Carvalho Chehab } 891c58b84eeSMauro Carvalho Chehab 892c58b84eeSMauro Carvalho Chehab ret: 893c58b84eeSMauro Carvalho Chehab mutex_unlock(&st->data_mutex); 894c58b84eeSMauro Carvalho Chehab return ret; 895786baecfSMauro Carvalho Chehab } 896786baecfSMauro Carvalho Chehab 897786baecfSMauro Carvalho Chehab static int af9005_power_ctrl(struct dvb_usb_device *d, int onoff) 898786baecfSMauro Carvalho Chehab { 899786baecfSMauro Carvalho Chehab 900786baecfSMauro Carvalho Chehab return 0; 901786baecfSMauro Carvalho Chehab } 902786baecfSMauro Carvalho Chehab 903786baecfSMauro Carvalho Chehab static int af9005_pid_filter_control(struct dvb_usb_adapter *adap, int onoff) 904786baecfSMauro Carvalho Chehab { 905786baecfSMauro Carvalho Chehab int ret; 906786baecfSMauro Carvalho Chehab deb_info("pid filter control onoff %d\n", onoff); 907786baecfSMauro Carvalho Chehab if (onoff) { 908786baecfSMauro Carvalho Chehab ret = 909786baecfSMauro Carvalho Chehab af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 1); 910786baecfSMauro Carvalho Chehab if (ret) 911786baecfSMauro Carvalho Chehab return ret; 912786baecfSMauro Carvalho Chehab ret = 913786baecfSMauro Carvalho Chehab af9005_write_register_bits(adap->dev, 914786baecfSMauro Carvalho Chehab XD_MP2IF_DMX_CTRL, 1, 1, 1); 915786baecfSMauro Carvalho Chehab if (ret) 916786baecfSMauro Carvalho Chehab return ret; 917786baecfSMauro Carvalho Chehab ret = 918786baecfSMauro Carvalho Chehab af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 1); 919786baecfSMauro Carvalho Chehab } else 920786baecfSMauro Carvalho Chehab ret = 921786baecfSMauro Carvalho Chehab af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 0); 922786baecfSMauro Carvalho Chehab if (ret) 923786baecfSMauro Carvalho Chehab return ret; 924786baecfSMauro Carvalho Chehab deb_info("pid filter control ok\n"); 925786baecfSMauro Carvalho Chehab return 0; 926786baecfSMauro Carvalho Chehab } 927786baecfSMauro Carvalho Chehab 928786baecfSMauro Carvalho Chehab static int af9005_pid_filter(struct dvb_usb_adapter *adap, int index, 929786baecfSMauro Carvalho Chehab u16 pid, int onoff) 930786baecfSMauro Carvalho Chehab { 931786baecfSMauro Carvalho Chehab u8 cmd = index & 0x1f; 932786baecfSMauro Carvalho Chehab int ret; 933786baecfSMauro Carvalho Chehab deb_info("set pid filter, index %d, pid %x, onoff %d\n", index, 934786baecfSMauro Carvalho Chehab pid, onoff); 935786baecfSMauro Carvalho Chehab if (onoff) { 936786baecfSMauro Carvalho Chehab /* cannot use it as pid_filter_ctrl since it has to be done 937786baecfSMauro Carvalho Chehab before setting the first pid */ 938786baecfSMauro Carvalho Chehab if (adap->feedcount == 1) { 939786baecfSMauro Carvalho Chehab deb_info("first pid set, enable pid table\n"); 940786baecfSMauro Carvalho Chehab ret = af9005_pid_filter_control(adap, onoff); 941786baecfSMauro Carvalho Chehab if (ret) 942786baecfSMauro Carvalho Chehab return ret; 943786baecfSMauro Carvalho Chehab } 944786baecfSMauro Carvalho Chehab ret = 945786baecfSMauro Carvalho Chehab af9005_write_ofdm_register(adap->dev, 946786baecfSMauro Carvalho Chehab XD_MP2IF_PID_DATA_L, 947786baecfSMauro Carvalho Chehab (u8) (pid & 0xff)); 948786baecfSMauro Carvalho Chehab if (ret) 949786baecfSMauro Carvalho Chehab return ret; 950786baecfSMauro Carvalho Chehab ret = 951786baecfSMauro Carvalho Chehab af9005_write_ofdm_register(adap->dev, 952786baecfSMauro Carvalho Chehab XD_MP2IF_PID_DATA_H, 953786baecfSMauro Carvalho Chehab (u8) (pid >> 8)); 954786baecfSMauro Carvalho Chehab if (ret) 955786baecfSMauro Carvalho Chehab return ret; 956786baecfSMauro Carvalho Chehab cmd |= 0x20 | 0x40; 957786baecfSMauro Carvalho Chehab } else { 958786baecfSMauro Carvalho Chehab if (adap->feedcount == 0) { 959786baecfSMauro Carvalho Chehab deb_info("last pid unset, disable pid table\n"); 960786baecfSMauro Carvalho Chehab ret = af9005_pid_filter_control(adap, onoff); 961786baecfSMauro Carvalho Chehab if (ret) 962786baecfSMauro Carvalho Chehab return ret; 963786baecfSMauro Carvalho Chehab } 964786baecfSMauro Carvalho Chehab } 965786baecfSMauro Carvalho Chehab ret = af9005_write_ofdm_register(adap->dev, XD_MP2IF_PID_IDX, cmd); 966786baecfSMauro Carvalho Chehab if (ret) 967786baecfSMauro Carvalho Chehab return ret; 968786baecfSMauro Carvalho Chehab deb_info("set pid ok\n"); 969786baecfSMauro Carvalho Chehab return 0; 970786baecfSMauro Carvalho Chehab } 971786baecfSMauro Carvalho Chehab 972786baecfSMauro Carvalho Chehab static int af9005_identify_state(struct usb_device *udev, 973786baecfSMauro Carvalho Chehab struct dvb_usb_device_properties *props, 974786baecfSMauro Carvalho Chehab struct dvb_usb_device_description **desc, 975786baecfSMauro Carvalho Chehab int *cold) 976786baecfSMauro Carvalho Chehab { 977786baecfSMauro Carvalho Chehab int ret; 978c58b84eeSMauro Carvalho Chehab u8 reply, *buf; 979c58b84eeSMauro Carvalho Chehab 980c58b84eeSMauro Carvalho Chehab buf = kmalloc(FW_BULKOUT_SIZE + 2, GFP_KERNEL); 981c58b84eeSMauro Carvalho Chehab if (!buf) 982c58b84eeSMauro Carvalho Chehab return -ENOMEM; 983c58b84eeSMauro Carvalho Chehab 984c58b84eeSMauro Carvalho Chehab ret = af9005_boot_packet(udev, FW_CONFIG, &reply, 985c58b84eeSMauro Carvalho Chehab buf, FW_BULKOUT_SIZE + 2); 986786baecfSMauro Carvalho Chehab if (ret) 987c58b84eeSMauro Carvalho Chehab goto err; 988786baecfSMauro Carvalho Chehab deb_info("result of FW_CONFIG in identify state %d\n", reply); 989786baecfSMauro Carvalho Chehab if (reply == 0x01) 990786baecfSMauro Carvalho Chehab *cold = 1; 991786baecfSMauro Carvalho Chehab else if (reply == 0x02) 992786baecfSMauro Carvalho Chehab *cold = 0; 993786baecfSMauro Carvalho Chehab else 994786baecfSMauro Carvalho Chehab return -EIO; 995786baecfSMauro Carvalho Chehab deb_info("Identify state cold = %d\n", *cold); 996c58b84eeSMauro Carvalho Chehab 997c58b84eeSMauro Carvalho Chehab err: 998c58b84eeSMauro Carvalho Chehab kfree(buf); 999c58b84eeSMauro Carvalho Chehab return ret; 1000786baecfSMauro Carvalho Chehab } 1001786baecfSMauro Carvalho Chehab 1002786baecfSMauro Carvalho Chehab static struct dvb_usb_device_properties af9005_properties; 1003786baecfSMauro Carvalho Chehab 1004786baecfSMauro Carvalho Chehab static int af9005_usb_probe(struct usb_interface *intf, 1005786baecfSMauro Carvalho Chehab const struct usb_device_id *id) 1006786baecfSMauro Carvalho Chehab { 1007c58b84eeSMauro Carvalho Chehab struct dvb_usb_device *d; 1008c58b84eeSMauro Carvalho Chehab struct af9005_device_state *st; 1009c58b84eeSMauro Carvalho Chehab int ret; 1010c58b84eeSMauro Carvalho Chehab 1011c58b84eeSMauro Carvalho Chehab ret = dvb_usb_device_init(intf, &af9005_properties, 1012c58b84eeSMauro Carvalho Chehab THIS_MODULE, &d, adapter_nr); 1013c58b84eeSMauro Carvalho Chehab 1014c58b84eeSMauro Carvalho Chehab if (ret < 0) 1015c58b84eeSMauro Carvalho Chehab return ret; 1016c58b84eeSMauro Carvalho Chehab 1017c58b84eeSMauro Carvalho Chehab st = d->priv; 1018c58b84eeSMauro Carvalho Chehab mutex_init(&st->data_mutex); 1019c58b84eeSMauro Carvalho Chehab 1020c58b84eeSMauro Carvalho Chehab return 0; 1021786baecfSMauro Carvalho Chehab } 1022786baecfSMauro Carvalho Chehab 1023786baecfSMauro Carvalho Chehab enum af9005_usb_table_entry { 1024786baecfSMauro Carvalho Chehab AFATECH_AF9005, 1025786baecfSMauro Carvalho Chehab TERRATEC_AF9005, 1026786baecfSMauro Carvalho Chehab ANSONIC_AF9005, 1027786baecfSMauro Carvalho Chehab }; 1028786baecfSMauro Carvalho Chehab 1029786baecfSMauro Carvalho Chehab static struct usb_device_id af9005_usb_table[] = { 1030786baecfSMauro Carvalho Chehab [AFATECH_AF9005] = {USB_DEVICE(USB_VID_AFATECH, 1031786baecfSMauro Carvalho Chehab USB_PID_AFATECH_AF9005)}, 1032786baecfSMauro Carvalho Chehab [TERRATEC_AF9005] = {USB_DEVICE(USB_VID_TERRATEC, 1033786baecfSMauro Carvalho Chehab USB_PID_TERRATEC_CINERGY_T_USB_XE)}, 1034786baecfSMauro Carvalho Chehab [ANSONIC_AF9005] = {USB_DEVICE(USB_VID_ANSONIC, 1035786baecfSMauro Carvalho Chehab USB_PID_ANSONIC_DVBT_USB)}, 1036786baecfSMauro Carvalho Chehab { } 1037786baecfSMauro Carvalho Chehab }; 1038786baecfSMauro Carvalho Chehab 1039786baecfSMauro Carvalho Chehab MODULE_DEVICE_TABLE(usb, af9005_usb_table); 1040786baecfSMauro Carvalho Chehab 1041786baecfSMauro Carvalho Chehab static struct dvb_usb_device_properties af9005_properties = { 1042786baecfSMauro Carvalho Chehab .caps = DVB_USB_IS_AN_I2C_ADAPTER, 1043786baecfSMauro Carvalho Chehab 1044786baecfSMauro Carvalho Chehab .usb_ctrl = DEVICE_SPECIFIC, 1045786baecfSMauro Carvalho Chehab .firmware = "af9005.fw", 1046786baecfSMauro Carvalho Chehab .download_firmware = af9005_download_firmware, 1047786baecfSMauro Carvalho Chehab .no_reconnect = 1, 1048786baecfSMauro Carvalho Chehab 1049786baecfSMauro Carvalho Chehab .size_of_priv = sizeof(struct af9005_device_state), 1050786baecfSMauro Carvalho Chehab 1051786baecfSMauro Carvalho Chehab .num_adapters = 1, 1052786baecfSMauro Carvalho Chehab .adapter = { 1053786baecfSMauro Carvalho Chehab { 1054786baecfSMauro Carvalho Chehab .num_frontends = 1, 1055786baecfSMauro Carvalho Chehab .fe = {{ 1056786baecfSMauro Carvalho Chehab .caps = 1057786baecfSMauro Carvalho Chehab DVB_USB_ADAP_HAS_PID_FILTER | 1058786baecfSMauro Carvalho Chehab DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, 1059786baecfSMauro Carvalho Chehab .pid_filter_count = 32, 1060786baecfSMauro Carvalho Chehab .pid_filter = af9005_pid_filter, 1061786baecfSMauro Carvalho Chehab /* .pid_filter_ctrl = af9005_pid_filter_control, */ 1062786baecfSMauro Carvalho Chehab .frontend_attach = af9005_frontend_attach, 1063786baecfSMauro Carvalho Chehab /* .tuner_attach = af9005_tuner_attach, */ 1064786baecfSMauro Carvalho Chehab /* parameter for the MPEG2-data transfer */ 1065786baecfSMauro Carvalho Chehab .stream = { 1066786baecfSMauro Carvalho Chehab .type = USB_BULK, 1067786baecfSMauro Carvalho Chehab .count = 10, 1068786baecfSMauro Carvalho Chehab .endpoint = 0x04, 1069786baecfSMauro Carvalho Chehab .u = { 1070786baecfSMauro Carvalho Chehab .bulk = { 1071786baecfSMauro Carvalho Chehab .buffersize = 4096, /* actual size seen is 3948 */ 1072786baecfSMauro Carvalho Chehab } 1073786baecfSMauro Carvalho Chehab } 1074786baecfSMauro Carvalho Chehab }, 1075786baecfSMauro Carvalho Chehab }}, 1076786baecfSMauro Carvalho Chehab } 1077786baecfSMauro Carvalho Chehab }, 1078786baecfSMauro Carvalho Chehab .power_ctrl = af9005_power_ctrl, 1079786baecfSMauro Carvalho Chehab .identify_state = af9005_identify_state, 1080786baecfSMauro Carvalho Chehab 1081786baecfSMauro Carvalho Chehab .i2c_algo = &af9005_i2c_algo, 1082786baecfSMauro Carvalho Chehab 1083786baecfSMauro Carvalho Chehab .rc.legacy = { 1084786baecfSMauro Carvalho Chehab .rc_interval = 200, 1085786baecfSMauro Carvalho Chehab .rc_map_table = NULL, 1086786baecfSMauro Carvalho Chehab .rc_map_size = 0, 1087786baecfSMauro Carvalho Chehab .rc_query = af9005_rc_query, 1088786baecfSMauro Carvalho Chehab }, 1089786baecfSMauro Carvalho Chehab 1090786baecfSMauro Carvalho Chehab .generic_bulk_ctrl_endpoint = 2, 1091786baecfSMauro Carvalho Chehab .generic_bulk_ctrl_endpoint_response = 1, 1092786baecfSMauro Carvalho Chehab 1093786baecfSMauro Carvalho Chehab .num_device_descs = 3, 1094786baecfSMauro Carvalho Chehab .devices = { 1095786baecfSMauro Carvalho Chehab {.name = "Afatech DVB-T USB1.1 stick", 1096786baecfSMauro Carvalho Chehab .cold_ids = {&af9005_usb_table[AFATECH_AF9005], NULL}, 1097786baecfSMauro Carvalho Chehab .warm_ids = {NULL}, 1098786baecfSMauro Carvalho Chehab }, 1099786baecfSMauro Carvalho Chehab {.name = "TerraTec Cinergy T USB XE", 1100786baecfSMauro Carvalho Chehab .cold_ids = {&af9005_usb_table[TERRATEC_AF9005], NULL}, 1101786baecfSMauro Carvalho Chehab .warm_ids = {NULL}, 1102786baecfSMauro Carvalho Chehab }, 1103786baecfSMauro Carvalho Chehab {.name = "Ansonic DVB-T USB1.1 stick", 1104786baecfSMauro Carvalho Chehab .cold_ids = {&af9005_usb_table[ANSONIC_AF9005], NULL}, 1105786baecfSMauro Carvalho Chehab .warm_ids = {NULL}, 1106786baecfSMauro Carvalho Chehab }, 1107786baecfSMauro Carvalho Chehab {NULL}, 1108786baecfSMauro Carvalho Chehab } 1109786baecfSMauro Carvalho Chehab }; 1110786baecfSMauro Carvalho Chehab 1111786baecfSMauro Carvalho Chehab /* usb specific object needed to register this driver with the usb subsystem */ 1112786baecfSMauro Carvalho Chehab static struct usb_driver af9005_usb_driver = { 1113786baecfSMauro Carvalho Chehab .name = "dvb_usb_af9005", 1114786baecfSMauro Carvalho Chehab .probe = af9005_usb_probe, 1115786baecfSMauro Carvalho Chehab .disconnect = dvb_usb_device_exit, 1116786baecfSMauro Carvalho Chehab .id_table = af9005_usb_table, 1117786baecfSMauro Carvalho Chehab }; 1118786baecfSMauro Carvalho Chehab 1119786baecfSMauro Carvalho Chehab /* module stuff */ 1120786baecfSMauro Carvalho Chehab static int __init af9005_usb_module_init(void) 1121786baecfSMauro Carvalho Chehab { 1122786baecfSMauro Carvalho Chehab int result; 1123786baecfSMauro Carvalho Chehab if ((result = usb_register(&af9005_usb_driver))) { 1124786baecfSMauro Carvalho Chehab err("usb_register failed. (%d)", result); 1125786baecfSMauro Carvalho Chehab return result; 1126786baecfSMauro Carvalho Chehab } 112722799487SFrank Schaefer #if IS_MODULE(CONFIG_DVB_USB_AF9005) || defined(CONFIG_DVB_USB_AF9005_REMOTE) 112822799487SFrank Schaefer /* FIXME: convert to todays kernel IR infrastructure */ 1129786baecfSMauro Carvalho Chehab rc_decode = symbol_request(af9005_rc_decode); 1130786baecfSMauro Carvalho Chehab rc_keys = symbol_request(rc_map_af9005_table); 1131786baecfSMauro Carvalho Chehab rc_keys_size = symbol_request(rc_map_af9005_table_size); 113222799487SFrank Schaefer #endif 1133786baecfSMauro Carvalho Chehab if (rc_decode == NULL || rc_keys == NULL || rc_keys_size == NULL) { 1134786baecfSMauro Carvalho Chehab err("af9005_rc_decode function not found, disabling remote"); 1135786baecfSMauro Carvalho Chehab af9005_properties.rc.legacy.rc_query = NULL; 1136786baecfSMauro Carvalho Chehab } else { 1137786baecfSMauro Carvalho Chehab af9005_properties.rc.legacy.rc_map_table = rc_keys; 1138786baecfSMauro Carvalho Chehab af9005_properties.rc.legacy.rc_map_size = *rc_keys_size; 1139786baecfSMauro Carvalho Chehab } 1140786baecfSMauro Carvalho Chehab 1141786baecfSMauro Carvalho Chehab return 0; 1142786baecfSMauro Carvalho Chehab } 1143786baecfSMauro Carvalho Chehab 1144786baecfSMauro Carvalho Chehab static void __exit af9005_usb_module_exit(void) 1145786baecfSMauro Carvalho Chehab { 1146786baecfSMauro Carvalho Chehab /* release rc decode symbols */ 1147786baecfSMauro Carvalho Chehab if (rc_decode != NULL) 1148786baecfSMauro Carvalho Chehab symbol_put(af9005_rc_decode); 1149786baecfSMauro Carvalho Chehab if (rc_keys != NULL) 1150786baecfSMauro Carvalho Chehab symbol_put(rc_map_af9005_table); 1151786baecfSMauro Carvalho Chehab if (rc_keys_size != NULL) 1152786baecfSMauro Carvalho Chehab symbol_put(rc_map_af9005_table_size); 1153786baecfSMauro Carvalho Chehab /* deregister this driver from the USB subsystem */ 1154786baecfSMauro Carvalho Chehab usb_deregister(&af9005_usb_driver); 1155786baecfSMauro Carvalho Chehab } 1156786baecfSMauro Carvalho Chehab 1157786baecfSMauro Carvalho Chehab module_init(af9005_usb_module_init); 1158786baecfSMauro Carvalho Chehab module_exit(af9005_usb_module_exit); 1159786baecfSMauro Carvalho Chehab 1160786baecfSMauro Carvalho Chehab MODULE_AUTHOR("Luca Olivetti <luca@ventoso.org>"); 1161786baecfSMauro Carvalho Chehab MODULE_DESCRIPTION("Driver for Afatech 9005 DVB-T USB1.1 stick"); 1162786baecfSMauro Carvalho Chehab MODULE_VERSION("1.0"); 1163786baecfSMauro Carvalho Chehab MODULE_LICENSE("GPL"); 1164