This device has the following chips on it: AF9015-NT* MXL5003S This device seems to work with the following additions to af9015.c in the tree found under: http://linuxtv.org/hg/~anttip/af9015-mxl500x/ Added under static struct usb_device_id af9015_usb_table[]: /* AverMedia DVB-T Volar X) */ {USB_DEVICE(0x07ca, 0xa815)}, Added/ changed under static struct dvb_usb_device_properties af9015_properties: .num_device_descs = 8, /* to add another case, without it the change didn't get picked up. */ and: { .name = " AverMedia DVB-T Volar X", .cold_ids = {&af9015_usb_table[8], NULL}, .warm_ids = {NULL}, }, With these changes, which are in attached file as well, the normal make, make install routine works and plugging the stick in to the usb-port it gets recognized and firmware of: http://www.otit.fi/~crope/v4l-dvb/af9015/af9015_firmware_cutter/firmware_files/4.95.0/ It can scan, tune and watch FTA-channels :) Hope this helps and can be added to the official driver somehow? Regards, Jos Hoekstra
/* * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver * * Copyright (C) 2007 Antti Palosaari <crope@xxxxxx> * * Thanks to Afatech who kindly provided information. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include "af9015.h" #include "af9013.h" #include "mt2060.h" #include "qt1010.h" #include "tda18271.h" #include "mxl500x.h" /* debug */ int dvb_usb_af9015_debug = 0x3d; module_param_named(debug, dvb_usb_af9015_debug, int, 0644); MODULE_PARM_DESC( debug, "set debugging level (1=info,xfer=2,rc=4,reg=8,i2c=16,fw=32 (or-able))." DVB_USB_DEBUG_STATUS); static struct af9013_config af9015_af9013_config[2] = { { .demod_address = AF9015_I2C_DEMOD, .ts_mode = AF9013_USB, }, { .demod_address = 0x3a, .ts_mode = AF9013_SERIAL_TS, } }; static int af9015_rw_udev(struct usb_device *udev, struct req_t *req) { int act_len, ret; u8 buf[64]; u8 write = 1; u8 msg_len = 8; static u8 seq; /* packet sequence number */ buf[0] = req->cmd; buf[1] = seq++; buf[2] = req->i2c_addr; buf[3] = req->addr >> 8; buf[4] = req->addr & 0xff; buf[5] = req->data0; buf[6] = req->data1; buf[7] = req->len; switch (req->cmd) { case GET_CONFIG: case BOOT: case READ_MEMORY: case RECONNECT_USB: case GET_IR_CODE: write = 0; break; case READ_I2C: write = 0; buf[2] |= 0x01; /* set I2C direction */ case WRITE_I2C: buf[0] = READ_WRITE_I2C; break; case WRITE_VIRTUAL_MEMORY: case WRITE_MEMORY: if (((req->addr & 0xff00) == 0xff00) || ((req->addr & 0xae00) == 0xae00)) buf[0] = WRITE_VIRTUAL_MEMORY; case COPY_FIRMWARE: case DOWNLOAD_FIRMWARE: break; default: err("%s: unknown command: %d", __func__, req->cmd); } /* write requested */ if (write) { memcpy(&buf[8], req->data, req->len); msg_len += req->len; } deb_xfer(">>> "); debug_dump(buf, msg_len, deb_xfer); /* send req */ ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x02), buf, msg_len, &act_len, AF9015_USB_TIMEOUT); if (ret) err("%s: sending failed: %d (%d/%d)", __func__, ret, msg_len, act_len); else if (act_len != msg_len) return -1; /* all data is not send */ /* no ack for those packets */ if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB) return 0; /* receive ack and data if read req */ msg_len = 1 + 1 + req->len; /* seq + status + data len */ ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, 0x81), buf, msg_len, &act_len, AF9015_USB_TIMEOUT); if (ret) { err("%s: receiving failed: %d", __func__, ret); return ret; } deb_xfer("<<< "); debug_dump(buf, act_len, deb_xfer); /* check status */ if (buf[1]) { err("%s: command failed: %d", __func__, buf[1]); return -1; } /* read request, copy returned data to return buf */ if (!write) memcpy(req->data, &buf[2], req->len); return 0; } static int af9015_rw(struct dvb_usb_device *d, struct req_t *req) { int ret; if (mutex_lock_interruptible(&d->i2c_mutex) < 0) return -EAGAIN; ret = af9015_rw_udev(d->udev, req); mutex_unlock(&d->i2c_mutex); return ret; } static int af9015_write_reg(struct dvb_usb_device *d, u16 addr, u8 val) { struct req_t req = { WRITE_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, 1, &val }; return af9015_rw(d, &req); } static int af9015_read_reg(struct dvb_usb_device *d, u16 addr, u8 *val) { struct req_t req = { READ_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, 1, val }; return af9015_rw(d, &req); } static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, u8 val) { struct req_t req = { WRITE_I2C, addr, reg, 1, 3, 1, &val }; return af9015_rw(d, &req); } static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, u8 *val) { struct req_t req = { READ_I2C, addr, reg, 0, 3, 1, val }; return af9015_rw(d, &req); } static int af9015_i2c_write_regs(struct dvb_usb_device *d, u8 addr, u8 reg, u8 *val, u8 count) { struct req_t req = { WRITE_I2C, addr, reg, 0, 1, count, val }; return af9015_rw(d, &req); } #if 0 static int af9015_i2c_write_reg(struct dvb_usb_device *d, u8 addr, u8 reg, u8 val) { return af9015_i2c_write_regs(d, addr, reg, &val, 1); } #endif static int af9015_i2c_read_reg(struct dvb_usb_device *d, u8 addr, u8 reg, u8 *val) { struct req_t req = { READ_I2C, addr, reg, 0, 1, 1, val }; return af9015_rw(d, &req); } #if 0 static int af9015_eeprom_write_reg(struct dvb_usb_device *d, u8 addr, u8 val) { return af9015_i2c_write_reg(d, AF9015_I2C_EEPROM, addr, val); } #endif static int af9015_eeprom_read_reg(struct dvb_usb_device *d, u8 addr, u8 *val) { return af9015_i2c_read_reg(d, AF9015_I2C_EEPROM, addr, val); } static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); int ret = 0; u16 addr; #if 0 if (mutex_lock_interruptible(&d->i2c_mutex) < 0) return -EAGAIN; #endif if (num > 2) { warn("more than 2 i2c messages at a time is not handled yet"); return -EINVAL; } if (msg[0].addr == AF9015_I2C_DEMOD || msg[0].addr == 0x3a) { /* 0x38 is targeted to demod */ addr = msg[0].buf[0] << 8; addr += msg[0].buf[1]; #if 1 if (msg[0].addr == AF9015_I2C_DEMOD) { if (num == 2) { /* reads a single register */ ret = af9015_read_reg(d, addr, &msg[1].buf[0]); if (!ret) ret = 2; } else { /* writes a single register */ ret = af9015_write_reg(d, addr, msg[0].buf[2]); if (!ret) ret = 1; } } else { if (num == 2) { /* reads a single register */ ret = af9015_read_reg_i2c(d, msg[0].addr, addr, &msg[1].buf[0]); if (!ret) ret = 2; } else { /* writes a single register */ ret = af9015_write_reg_i2c(d, msg[0].addr, addr, msg[0].buf[2]); if (!ret) ret = 1; } } #else if (num == 2) { /* reads a single register */ ret = af9015_read_reg_i2c(d, msg[0].addr, addr, &msg[1].buf[0]); if (!ret) ret = 2; } else { /* writes a single register */ ret = af9015_write_reg_i2c(d, msg[0].addr, addr, msg[0].buf[2]); if (!ret) ret = 1; } #endif } else { /* normal i2c request, for e.g. tuner */ if (num == 2) { /* reads a single register */ ret = af9015_i2c_read_reg(d, msg[0].addr, *msg[0].buf, msg[1].buf); if (!ret) ret = 2; } else { /* writes a single register */ ret = af9015_i2c_write_regs(d, msg[0].addr, msg[0].buf[0], &msg[0].buf[1], msg[0].len-1); if (!ret) ret = 1; } } #if 0 mutex_unlock(&d->i2c_mutex); #endif return ret; } static u32 af9015_i2c_func(struct i2c_adapter *adapter) { return I2C_FUNC_I2C; } static struct i2c_algorithm af9015_i2c_algo = { .master_xfer = af9015_i2c_xfer, .functionality = af9015_i2c_func, }; static int af9015_do_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit, u8 op) { int ret; u8 val, mask = 0x01; ret = af9015_read_reg(d, addr, &val); if (ret) return ret; mask <<= bit; if (op) { /* set bit */ val |= mask; } else { /* clear bit */ mask ^= 0xff; val &= mask; } return af9015_write_reg(d, addr, val); } static int af9015_set_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit) { return af9015_do_reg_bit(d, addr, bit, 1); } static int af9015_clear_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit) { return af9015_do_reg_bit(d, addr, bit, 0); } static int af9015_init_endpoint(struct dvb_usb_device *d) { int ret; struct af9015_state *state = d->priv; u16 frame_size; u8 packet_size; deb_info("%s: USB speed:%d\n", __func__, d->udev->speed); #define TS_PACKET_SIZE 188 #define TS_USB20_PACKET_COUNT 348 #define TS_USB20_FRAME_SIZE (TS_PACKET_SIZE*TS_USB20_PACKET_COUNT) #define TS_USB11_PACKET_COUNT 21 #define TS_USB11_FRAME_SIZE (TS_PACKET_SIZE*TS_USB11_PACKET_COUNT) #define TS_USB20_MAX_PACKET_SIZE 512 #define TS_USB11_MAX_PACKET_SIZE 64 if (d->udev->speed == USB_SPEED_FULL) { frame_size = TS_USB11_FRAME_SIZE/4; packet_size = TS_USB11_MAX_PACKET_SIZE/4; } else { frame_size = TS_USB20_FRAME_SIZE/4; packet_size = TS_USB20_MAX_PACKET_SIZE/4; } ret = af9015_set_reg_bit(d, 0xd507, 2); /* assert EP4 reset */ if (ret) goto exit; ret = af9015_set_reg_bit(d, 0xd50b, 1); /* assert EP5 reset */ if (ret) goto exit; ret = af9015_clear_reg_bit(d, 0xdd11, 5); /* disable EP4 */ if (ret) goto exit; ret = af9015_clear_reg_bit(d, 0xdd11, 6); /* disable EP5 */ if (ret) goto exit; ret = af9015_set_reg_bit(d, 0xdd11, 5); /* enable EP4 */ if (ret) goto exit; if (state->dual_mode) { ret = af9015_set_reg_bit(d, 0xdd11, 6); /* enable EP5 */ if (ret) goto exit; } ret = af9015_clear_reg_bit(d, 0xdd13, 5); /* disable EP4 NAK */ if (ret) goto exit; if (state->dual_mode) { ret = af9015_clear_reg_bit(d, 0xdd13, 6); /* disable EP5 NAK */ if (ret) goto exit; } /* EP4 xfer length */ ret = af9015_write_reg(d, 0xdd88, frame_size & 0xff); if (ret) goto exit; ret = af9015_write_reg(d, 0xdd89, frame_size >> 8); if (ret) goto exit; /* EP5 xfer length */ ret = af9015_write_reg(d, 0xdd8a, frame_size & 0xff); if (ret) goto exit; ret = af9015_write_reg(d, 0xdd8b, frame_size >> 8); if (ret) goto exit; ret = af9015_write_reg(d, 0xdd0c, packet_size); /* EP4 packet size */ if (ret) goto exit; ret = af9015_write_reg(d, 0xdd0d, packet_size); /* EP5 packet size */ if (ret) goto exit; ret = af9015_clear_reg_bit(d, 0xd507, 2); /* negate EP4 reset */ if (ret) goto exit; if (state->dual_mode) { ret = af9015_clear_reg_bit(d, 0xd50b, 1); /* negate EP5 reset */ if (ret) goto exit; } /* enable / disable mp2if2 */ if (state->dual_mode) ret = af9015_set_reg_bit(d, 0xd50b, 0); else ret = af9015_clear_reg_bit(d, 0xd50b, 0); exit: if (ret) err("%s: failed:%d", __func__, ret); return ret; } #define MERC_FW_DOWNLOAD_BASE 0x5100 #define MERC_FW_STATUS 0x98be #define MERC_BOOT_REQUEST 0xe205 static int af9015_copy_firmware(struct dvb_usb_device *d) { int ret; u8 buf[] = { 0x3e, 0x29, 0x98, 0x8d }; /* FW len & checksum FIXME */ u8 val; struct req_t req = { COPY_FIRMWARE, 0, MERC_FW_DOWNLOAD_BASE, 0, 0, sizeof(buf), buf }; deb_info("%s:\n", __func__); /* check firmware status */ ret = af9015_read_reg_i2c(d, 0x3a, MERC_FW_STATUS, &val); if (ret) goto exit; deb_info("%s: firmware status:%02x\n", __func__, val); /* copy firmware */ /* set I2C master clock to fast */ ret = af9015_write_reg(d, 0xd416, 0x04); /* 0x04 * 400ns */ if (ret) goto exit; msleep(50); ret = af9015_rw(d, &req); if (ret) goto exit; /* set I2C master clock back to normal */ ret = af9015_write_reg(d, 0xd416, 0x01); /* 0x14 * 400ns */ if (ret) goto exit; msleep(100); /* request boot firmware */ ret = af9015_write_reg_i2c(d, 0x3a, MERC_BOOT_REQUEST, 1); if (ret) goto exit; msleep(100); /* check firmware status */ ret = af9015_read_reg_i2c(d, 0x3a, MERC_FW_STATUS, &val); if (ret) goto exit; exit: if (ret) { err("%s: failed, err:%d", __func__, ret); deb_info("%s: failed, err:%d\n", __func__, ret); } return ret; } /* dump eeprom */ static int af9015_eeprom_dump(struct dvb_usb_device *d) { char buf[52], buf2[4]; u8 reg, val; deb_info("%s:\n", __func__); for (reg = 0; ; reg++) { if (reg % 16 == 0) { if (reg) deb_info("%s\n", buf); sprintf(buf, "%02x: ", reg); } if (af9015_eeprom_read_reg(d, reg, &val) == 0) sprintf(buf2, "%02x ", val); else strcpy(buf2, "-- "); strcat(buf, buf2); if (reg == 0xff) break; } deb_info("%s\n", buf); return 0; } int af9015_download_ir_table(struct dvb_usb_device *d) { int i, packets, ret; u16 addr = 0x9a56; /* ir-table start address */ struct req_t req = { WRITE_MEMORY, AF9015_I2C_DEMOD, 0, 0, 0, 1, NULL }; deb_info("%s:\n", __func__); packets = sizeof(ir_table); for (i = 0; i < packets; i++) { req.addr = addr + i; req.data = &ir_table[i]; ret = af9015_rw(d, &req); if (ret) { err("%s: ir-table download failed at packet %d with " \ "code %d", __func__, i, ret); return ret; } } return 0; } static int af9015_set_gpio(struct dvb_usb_device *d, u8 gpio, u8 gpioval) { int ret; u8 regval; u16 addr; deb_info("%s: gpio:%d gpioval:%02x\n", __func__, gpio, gpioval); /* GPIO0 & GPIO1 0xd735 GPIO2 & GPIO3 0xd736 */ switch (gpio) { case 0: case 1: addr = 0xd735; break; case 2: case 3: addr = 0xd736; break; default: err("%s: invalid gpio:%d\n", __func__, gpio); ret = -EINVAL; goto exit; }; ret = af9015_read_reg(d, addr, ®val); if (ret) goto exit; switch (gpio) { case 0: case 2: regval &= 0xf0; regval |= (gpioval << 0); break; case 1: case 3: regval &= 0x0f; regval |= (gpioval << 4); break; }; ret = af9015_write_reg(d, addr, regval); exit: if (ret) err("%s: failed, err:%d", __func__, ret); return ret; } static int af9015_init(struct dvb_usb_device *d) { int ret; deb_info("%s:\n", __func__); ret = af9015_init_endpoint(d); if (ret) goto exit; ret = af9015_download_ir_table(d); if (ret) goto exit; exit: return ret; } static int af9015_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) { int ret; deb_info("%s: onoff:%d\n", __func__, onoff); #if 0 if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0) return -EAGAIN; #endif if (onoff) ret = af9015_set_reg_bit(adap->dev, 0xd503, 0); else ret = af9015_clear_reg_bit(adap->dev, 0xd503, 0); #if 0 mutex_unlock(&adap->dev->i2c_mutex); #endif return ret; } static int af9015_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff) { int ret; u8 idx; deb_info("%s: set pid filter, index %d, pid %x, onoff %d\n", __func__, index, pid, onoff); #if 0 if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0) return -EAGAIN; #endif ret = af9015_write_reg(adap->dev, 0xd505, (pid & 0xff)); if (ret) goto exit; ret = af9015_write_reg(adap->dev, 0xd506, (pid >> 8)); if (ret) goto exit; idx = ((index & 0x1f) | (1 << 5)); ret = af9015_write_reg(adap->dev, 0xd504, idx); exit: #if 0 mutex_unlock(&adap->dev->i2c_mutex); #endif return ret; } static int af9015_download_firmware(struct usb_device *udev, const struct firmware *fw) { int i, len, packets, remainder, ret; struct req_t req = { DOWNLOAD_FIRMWARE, AF9015_I2C_DEMOD, 0, 0, 0, 0, NULL }; u16 addr = 0x5100; /* firmware start address */ u8 tmp; deb_info("%s:\n", __func__); #define FW_PACKET_MAX_DATA 55 packets = fw->size / FW_PACKET_MAX_DATA; remainder = fw->size % FW_PACKET_MAX_DATA; len = FW_PACKET_MAX_DATA; for (i = 0; i <= packets; i++) { if (i == packets) /* set size of the last packet */ len = remainder; req.len = len; req.data = (fw->data + i * FW_PACKET_MAX_DATA); req.addr = addr; addr += FW_PACKET_MAX_DATA; ret = af9015_rw_udev(udev, &req); if (ret) { err("%s: firmware download failed at packet %d with " \ "code %d", __func__, i, ret); goto exit; } } #undef FW_PACKET_MAX_DATA /* firmware loaded, request boot */ req.cmd = BOOT; ret = af9015_rw_udev(udev, &req); if (ret) { err("%s: boot failed: %d", __func__, ret); goto exit; } #if 0 msleep(1); /* boot done, ensure that firmware is running */ req.cmd = GET_CONFIG; req.len = 1; req.data = &tmp; ret = af9015_rw_udev(udev, &req); if (ret) { err("%s: get config failed: %d", __func__, ret); goto exit; } if (tmp != 0x02) { err("%s: firmware did not run (%02x)", __func__, tmp); return -EIO; } #endif #if 1 /* firmware is running, reconnect device in the usb bus */ req.cmd = RECONNECT_USB; ret = af9015_rw_udev(udev, &req); if (ret) err("%s: reconnect failed: %d", __func__, ret); #endif exit: return ret; } static int af9015_read_config(struct dvb_usb_device *d) { int ret; struct af9015_state *state = d->priv; u8 val; #if 0 /* remote */ ret = af9015_eeprom_read_reg(d, AF9015_EEPROM_IR_MODE, &val); if (ret) goto exit; deb_info("%s: ir mode:%d\n", __func__, val); ret = af9015_eeprom_read_reg(d, AF9015_EEPROM_IR_REMOTE_TYPE, &val); if (ret) goto exit; deb_info("%s: ir remote type:%d\n", __func__, val); #endif /* TS mode - one or two receivers */ ret = af9015_eeprom_read_reg(d, AF9015_EEPROM_TS_MODE, &val); if (ret) goto exit; state->dual_mode = val; deb_info("%s: TS mode:%d\n", __func__, val); /* xtal */ ret = af9015_eeprom_read_reg(d, AF9015_EEPROM_XTAL_TYPE1, &val); if (ret) goto exit; switch (val) { case 0: af9015_af9013_config[0].adc_clock = 28800; af9015_af9013_config[1].adc_clock = 28800; break; case 1: af9015_af9013_config[0].adc_clock = 20480; af9015_af9013_config[1].adc_clock = 20480; break; case 2: af9015_af9013_config[0].adc_clock = 28000; af9015_af9013_config[1].adc_clock = 28000; break; case 3: af9015_af9013_config[0].adc_clock = 25000; af9015_af9013_config[1].adc_clock = 25000; break; }; deb_info("%s: xtal:%d set adc_clock:%d\n", __func__, val, af9015_af9013_config[0].adc_clock); /* tuner IF */ ret = af9015_eeprom_read_reg(d, AF9015_EEPROM_IF1H, &val); if (ret) goto exit; af9015_af9013_config[0].tuner_if = val << 8; ret = af9015_eeprom_read_reg(d, AF9015_EEPROM_IF1L, &val); if (ret) goto exit; af9015_af9013_config[0].tuner_if += val; deb_info("%s: IF1:%d\n", __func__, af9015_af9013_config[0].tuner_if); af9015_af9013_config[1].tuner_if = af9015_af9013_config[0].tuner_if; /* MT2060 IF1 */ ret = af9015_eeprom_read_reg(d, AF9015_EEPROM_MT2060_IF1H, &val); if (ret) goto exit; state->mt2060_if1 = val << 8; ret = af9015_eeprom_read_reg(d, AF9015_EEPROM_MT2060_IF1L, &val); if (ret) goto exit; state->mt2060_if1 += val; deb_info("%s: MT2060 IF1:%d\n", __func__, state->mt2060_if1); /* tuner */ ret = af9015_eeprom_read_reg(d, AF9015_EEPROM_TUNER_ID1, &val); if (ret) goto exit; switch (val) { case AF9013_TUNER_MT2060: case AF9013_TUNER_QT1010: case AF9013_TUNER_TDA18271: af9015_af9013_config[0].rf_spec_inv = 1; break; case AF9013_TUNER_MXL5003D: case AF9013_TUNER_MXL5005D: case AF9013_TUNER_MXL5005R: af9015_af9013_config[0].rf_spec_inv = 0; af9015_af9013_config[1].rf_spec_inv = 0; break; default: warn("%s: tuner id:%d not supported, please report!", __func__, val); return -ENODEV; }; af9015_af9013_config[0].tuner = val; af9015_af9013_config[1].tuner = val; deb_info("%s: tuner id1:%d\n", __func__, val); /* spectral inversion */ ret = af9015_eeprom_read_reg(d, AF9015_EEPROM_SPEC_INV1, &val); if (ret) goto exit; /* does this really have any meaning? looks like it is always 0... af9015_af9013_config.rf_spec_inv = val; */ deb_info("%s: spectral inversion:%d\n", __func__, val); exit: if (ret) err("%s: eeprom read failed, err:%d", __func__, ret); return ret; } static int af9015_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props, struct dvb_usb_device_description **desc, int *cold) { int ret; u8 reply; struct req_t req = { GET_CONFIG, AF9015_I2C_DEMOD, 0, 0, 0, 1, &reply }; ret = af9015_rw_udev(udev, &req); if (ret) return ret; deb_info("%s: reply:%02x\n", __func__, reply); if (reply == 0x02) *cold = 0; else *cold = 1; return ret; } /* A-Link DTU(m) */ static struct dvb_usb_rc_key af9015_rc_keys[] = { { 0x00, 0x1e, KEY_1 }, { 0x00, 0x1f, KEY_2 }, { 0x00, 0x20, KEY_3 }, { 0x00, 0x21, KEY_4 }, { 0x00, 0x22, KEY_5 }, { 0x00, 0x23, KEY_6 }, { 0x00, 0x24, KEY_7 }, { 0x00, 0x25, KEY_8 }, { 0x00, 0x26, KEY_9 }, { 0x00, 0x27, KEY_0 }, { 0x00, 0x2e, KEY_CHANNELUP }, { 0x00, 0x2d, KEY_CHANNELDOWN }, { 0x04, 0x28, KEY_ZOOM }, { 0x00, 0x41, KEY_MUTE }, { 0x00, 0x42, KEY_VOLUMEDOWN }, { 0x00, 0x43, KEY_VOLUMEUP }, { 0x00, 0x44, KEY_GOTO }, /* jump */ { 0x05, 0x45, KEY_POWER }, }; static int af9015_rc_query(struct dvb_usb_device *d, u32 *event, int *state) { u8 buf[8]; struct req_t req = { GET_IR_CODE, 0, 0, 0, 0, sizeof(buf), buf }; struct dvb_usb_rc_key *keymap = d->props.rc_key_map; int i, ret; #if 0 if (mutex_lock_interruptible(&d->i2c_mutex) < 0) return -EAGAIN; #endif ret = af9015_rw(d, &req); #if 0 mutex_unlock(&d->i2c_mutex); #endif if (ret) return ret; *event = 0; *state = REMOTE_NO_KEY_PRESSED; for (i = 0; i < d->props.rc_key_map_size; i++) { if (keymap[i].custom == buf[0] && keymap[i].data == buf[2]) { *event = keymap[i].event; *state = REMOTE_KEY_PRESSED; return 0; } } return 0; } static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) { int ret; struct af9015_state *state = adap->dev->priv; /* dump eeprom (debug) */ ret = af9015_eeprom_dump(adap->dev); if (ret) return ret; /* read configuration from eeprom */ ret = af9015_read_config(adap->dev); if (ret) return ret; /* copy firmware to 2nd demodulator */ if (state->dual_mode) { ret = af9015_copy_firmware(adap->dev); if (ret) { info("%s: firmware copy to 2nd frontend failed, " \ "will disable it", __func__); state->dual_mode = 0; ret = 0; } } /* attach demodulator */ adap->fe = dvb_attach(af9013_attach, &af9015_af9013_config[0], &adap->dev->i2c_adap); if (adap->fe != NULL) return 0; return -EIO; } static int af9015_af9013_frontend2_attach(struct dvb_usb_adapter *adap) { struct af9015_state *state = adap->dev->priv; /* attach 2nd demodulator */ if (state->dual_mode) { adap->fe = dvb_attach(af9013_attach, &af9015_af9013_config[1], &adap->dev->i2c_adap); if (adap->fe != NULL) return 0; } return -EIO; } static struct mt2060_config af9015_mt2060_config = { .i2c_address = 0xc0, .clock_out = 0, }; static struct qt1010_config af9015_qt1010_config = { .i2c_address = 0xc4, }; static struct tda18271_config af9015_tda18271_config = { .gate = TDA18271_GATE_DIGITAL, .small_i2c = 1, }; static struct mxl500x_config af9015_mxl5003_config = { .delsys = MXL500x_MODE_DVBT, .octf = 0, .xtal_freq = 16000000, .iflo_freq = 4570000, .ref_freq = 365600000, .rssi_ena = 0, .addr = 0xc6, }; static struct mxl500x_config af9015_mxl5005_config = { .delsys = MXL500x_MODE_DVBT, .octf = MXL500x_OCTF_OFF, .xtal_freq = 16000000, .iflo_freq = 4570000, .ref_freq = 365600000, .rssi_ena = 0, .addr = 0xc6, }; static int af9015_tuner_attach(struct dvb_usb_adapter *adap) { struct af9015_state *state = adap->dev->priv; int ret = 0; deb_info("%s: \n", __func__); #if 0 /* connect tuner */ switch (af9015_af9013_config[0].tuner) { case AF9013_TUNER_MT2060: case AF9013_TUNER_QT1010: case AF9013_TUNER_TDA18271: ret = af9015_set_gpio(adap->dev, 3, AF9015_GPIO_TUNER_ON); break; case AF9013_TUNER_MXL5003D: case AF9013_TUNER_MXL5005D: case AF9013_TUNER_MXL5005R: ret = af9015_set_gpio(adap->dev, 1, AF9015_GPIO_TUNER_ON); if (state->dual_mode) ret = af9015_set_gpio(adap->dev, 0, AF9015_GPIO_TUNER_ON); break; } if (ret) return ret; #endif switch (af9015_af9013_config[0].tuner) { case AF9013_TUNER_MT2060: ret = dvb_attach(mt2060_attach, adap->fe, &adap->dev->i2c_adap, &af9015_mt2060_config, state->mt2060_if1) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_QT1010: ret = dvb_attach(qt1010_attach, adap->fe, &adap->dev->i2c_adap, &af9015_qt1010_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_TDA18271: ret = dvb_attach(tda18271_attach, adap->fe, 0xc0, &adap->dev->i2c_adap, &af9015_tda18271_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MXL5003D: ret = dvb_attach(mxl500x_attach, adap->fe, &af9015_mxl5003_config, &adap->dev->i2c_adap) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MXL5005D: case AF9013_TUNER_MXL5005R: ret = dvb_attach(mxl500x_attach, adap->fe, &af9015_mxl5005_config, &adap->dev->i2c_adap) == NULL ? -ENODEV : 0; break; default: ret = -EINVAL; err("%s: Unknown tuner id:%d", __func__, af9015_af9013_config[0].tuner); } return ret; } static struct dvb_usb_device_properties af9015_properties; static int af9015_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { int ret = 0; struct dvb_usb_device *d = NULL; deb_info("%s: interface:%d\n", __func__, intf->cur_altsetting->desc.bInterfaceNumber); /* interface 0 is used by DVB-T receiver and interface 1 is for remote controller (HID) */ if (intf->cur_altsetting->desc.bInterfaceNumber == 0) { ret = dvb_usb_device_init(intf, &af9015_properties, THIS_MODULE, &d); if (ret) return ret; if (d) ret = af9015_init(d); } return ret; } static struct usb_device_id af9015_usb_table[] = { {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9015)}, {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9016)}, {USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_GOLD)}, {USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_71E)}, /* KWorld PlusTV Dual DVB-T Stick (DVB-T 399U) */ {USB_DEVICE(0x1b80, 0xe399)}, {USB_DEVICE(USB_VID_VISIONPLUS, 0x3226)}, /* TwinHan AzureWave AD-TU700(704J) */ {USB_DEVICE(USB_VID_VISIONPLUS, 0x3237)}, /* TerraTec Cinergy T USB XE (Rev. 2) */ {USB_DEVICE(USB_VID_TERRATEC, 0x0069)}, /* AverMedia DVB-T Volar X) */ {USB_DEVICE(0x07ca, 0xa815)}, {0}, }; MODULE_DEVICE_TABLE(usb, af9015_usb_table); static struct dvb_usb_device_properties af9015_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, .i2c_algo = &af9015_i2c_algo, .usb_ctrl = DEVICE_SPECIFIC, .size_of_priv = sizeof(struct af9015_state), #if 0 .rc_interval = 200, .rc_key_map = af9015_rc_keys, .rc_key_map_size = ARRAY_SIZE(af9015_rc_keys), .rc_query = af9015_rc_query, #endif .identify_state = af9015_identify_state, .firmware = "dvb-usb-af9015.fw", .download_firmware = af9015_download_firmware, .num_adapters = 2, .adapter = { { #if 0 .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, .pid_filter = af9015_pid_filter, .pid_filter_ctrl = af9015_pid_filter_ctrl, #endif .frontend_attach = af9015_af9013_frontend_attach, .tuner_attach = af9015_tuner_attach, .stream = { .type = USB_BULK, .count = 6, .endpoint = 0x84, .u = { .bulk = { .buffersize = TS_USB20_FRAME_SIZE, } } }, }, { #if 0 .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, .pid_filter = af9015_pid_filter, .pid_filter_ctrl = af9015_pid_filter_ctrl, #endif .frontend_attach = af9015_af9013_frontend2_attach, .tuner_attach = af9015_tuner_attach, .stream = { .type = USB_BULK, .count = 6, .endpoint = 0x85, .u = { .bulk = { .buffersize = TS_USB20_FRAME_SIZE, } } }, } }, .num_device_descs = 8, .devices = { { .name = "Afatech AF9015 DVB-T USB2.0 stick", .cold_ids = {&af9015_usb_table[0], &af9015_usb_table[1], NULL}, .warm_ids = {NULL}, }, { .name = "Leadtek WinFast DTV Dongle Gold", .cold_ids = {&af9015_usb_table[2], NULL}, .warm_ids = {NULL}, }, { .name = "Pinnacle PCTV 71e", .cold_ids = {&af9015_usb_table[3], NULL}, .warm_ids = {NULL}, }, { .name = "KWorld PlusTV Dual DVB-T Stick (DVB-T 399U)", .cold_ids = {&af9015_usb_table[4], NULL}, .warm_ids = {NULL}, }, { .name = "DigitalNow TinyTwin DVB-T Receiver", .cold_ids = {&af9015_usb_table[5], NULL}, .warm_ids = {NULL}, }, { .name = "TwinHan AzureWave AD-TU700(704J)", .cold_ids = {&af9015_usb_table[6], NULL}, .warm_ids = {NULL}, }, { .name = "TerraTec Cinergy T USB XE", .cold_ids = {&af9015_usb_table[7], NULL}, .warm_ids = {NULL}, }, { .name = " AverMedia DVB-T Volar X", .cold_ids = {&af9015_usb_table[8], NULL}, .warm_ids = {NULL}, }, {NULL}, } }; /* usb specific object needed to register this driver with the usb subsystem */ static struct usb_driver af9015_usb_driver = { #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 15) .owner = THIS_MODULE, #endif .name = "dvb_usb_af9015", .probe = af9015_usb_probe, .disconnect = dvb_usb_device_exit, .id_table = af9015_usb_table, }; /* module stuff */ static int __init af9015_usb_module_init(void) { int ret; ret = usb_register(&af9015_usb_driver); if (ret) err("%s: usb_register failed. Error number %d", __func__, ret); return ret; } static void __exit af9015_usb_module_exit(void) { /* deregister this driver from the USB subsystem */ usb_deregister(&af9015_usb_driver); } module_init(af9015_usb_module_init); module_exit(af9015_usb_module_exit); MODULE_AUTHOR("Antti Palosaari <crope@xxxxxx>"); MODULE_DESCRIPTION("Driver for Afatech AF9015 DVB-T"); MODULE_LICENSE("GPL");
Stuff on Chips: AF9015-NT* 0729 HKH2T MXL5003S D37t3.21 0732 Bus 007 Device 003: ID 07ca:a815 AVerMedia Technologies, Inc. Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 0 (Defined at Interface level) bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 idVendor 0x07ca AVerMedia Technologies, Inc. idProduct 0xa815 bcdDevice 2.00 iManufacturer 1 AVerMedia iProduct 2 A815 iSerial 3 300700301156000 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 71 bNumInterfaces 2 bConfigurationValue 1 iConfiguration 0 bmAttributes 0x80 (Bus Powered) MaxPower 500mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 4 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x84 EP 4 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x85 EP 5 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 3 Human Interface Device bInterfaceSubClass 0 No Subclass bInterfaceProtocol 1 Keyboard iInterface 0 HID Device Descriptor: bLength 9 bDescriptorType 33 bcdHID 1.01 bCountryCode 0 Not supported bNumDescriptors 1 bDescriptorType 34 Report wDescriptorLength 65 Report Descriptors: ** UNAVAILABLE ** Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x83 EP 3 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 16 Device Qualifier (for other device speed): bLength 10 bDescriptorType 6 bcdUSB 2.00 bDeviceClass 0 (Defined at Interface level) bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 bNumConfigurations 1 Device Status: 0x0000 (Bus Powered)
_______________________________________________ linux-dvb mailing list linux-dvb@xxxxxxxxxxx http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb