📄 af9005.c
字号:
memset(ibuf, 0, sizeof(ibuf)); obuf[0] = 14; /* length of rest of packet low */ obuf[1] = 0; /* length of rest of packer high */ obuf[2] = 0x2a; /* read/write eeprom */ obuf[3] = 12; /* size */ obuf[4] = st->sequence++; obuf[5] = 0; /* read */ obuf[6] = len; obuf[7] = address; ret = af9005_usb_generic_rw(d, obuf, 16, ibuf, 14, 0); if (ret) return ret; if (ibuf[2] != 0x2b) { err("Read eeprom, invalid reply code"); return -EIO; } if (ibuf[3] != 10) { err("Read eeprom, invalid reply length"); return -EIO; } if (ibuf[4] != obuf[4]) { err("Read eeprom, wrong sequence in reply "); return -EIO; } if (ibuf[5] != 1) { err("Read eeprom, wrong status in reply "); return -EIO; } for (i = 0; i < len; i++) { values[i] = ibuf[6 + i]; } return 0;}static int af9005_boot_packet(struct usb_device *udev, int type, u8 * reply){ u8 buf[FW_BULKOUT_SIZE + 2]; u16 checksum; int act_len, i, ret; memset(buf, 0, sizeof(buf)); buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff); buf[1] = (u8) ((FW_BULKOUT_SIZE >> 8) & 0xff); switch (type) { case FW_CONFIG: buf[2] = 0x11; buf[3] = 0x04; buf[4] = 0x00; /* sequence number, original driver doesn't increment it here */ buf[5] = 0x03; checksum = buf[4] + buf[5]; buf[6] = (u8) ((checksum >> 8) & 0xff); buf[7] = (u8) (checksum & 0xff); break; case FW_CONFIRM: buf[2] = 0x11; buf[3] = 0x04; buf[4] = 0x00; /* sequence number, original driver doesn't increment it here */ buf[5] = 0x01; checksum = buf[4] + buf[5]; buf[6] = (u8) ((checksum >> 8) & 0xff); buf[7] = (u8) (checksum & 0xff); break; case FW_BOOT: buf[2] = 0x10; buf[3] = 0x08; buf[4] = 0x00; /* sequence number, original driver doesn't increment it here */ buf[5] = 0x97; buf[6] = 0xaa; buf[7] = 0x55; buf[8] = 0xa5; buf[9] = 0x5a; checksum = 0; for (i = 4; i <= 9; i++) checksum += buf[i]; buf[10] = (u8) ((checksum >> 8) & 0xff); buf[11] = (u8) (checksum & 0xff); break; default: err("boot packet invalid boot packet type"); return -EINVAL; } deb_fw(">>> "); debug_dump(buf, FW_BULKOUT_SIZE + 2, deb_fw); ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x02), buf, FW_BULKOUT_SIZE + 2, &act_len, 2000); if (ret) err("boot packet bulk message failed: %d (%d/%d)", ret, FW_BULKOUT_SIZE + 2, act_len); else ret = act_len != FW_BULKOUT_SIZE + 2 ? -1 : 0; if (ret) return ret; memset(buf, 0, 9); ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, 0x01), buf, 9, &act_len, 2000); if (ret) { err("boot packet recv bulk message failed: %d", ret); return ret; } deb_fw("<<< "); debug_dump(buf, act_len, deb_fw); checksum = 0; switch (type) { case FW_CONFIG: if (buf[2] != 0x11) { err("boot bad config header."); return -EIO; } if (buf[3] != 0x05) { err("boot bad config size."); return -EIO; } if (buf[4] != 0x00) { err("boot bad config sequence."); return -EIO; } if (buf[5] != 0x04) { err("boot bad config subtype."); return -EIO; } for (i = 4; i <= 6; i++) checksum += buf[i]; if (buf[7] * 256 + buf[8] != checksum) { err("boot bad config checksum."); return -EIO; } *reply = buf[6]; break; case FW_CONFIRM: if (buf[2] != 0x11) { err("boot bad confirm header."); return -EIO; } if (buf[3] != 0x05) { err("boot bad confirm size."); return -EIO; } if (buf[4] != 0x00) { err("boot bad confirm sequence."); return -EIO; } if (buf[5] != 0x02) { err("boot bad confirm subtype."); return -EIO; } for (i = 4; i <= 6; i++) checksum += buf[i]; if (buf[7] * 256 + buf[8] != checksum) { err("boot bad confirm checksum."); return -EIO; } *reply = buf[6]; break; case FW_BOOT: if (buf[2] != 0x10) { err("boot bad boot header."); return -EIO; } if (buf[3] != 0x05) { err("boot bad boot size."); return -EIO; } if (buf[4] != 0x00) { err("boot bad boot sequence."); return -EIO; } if (buf[5] != 0x01) { err("boot bad boot pattern 01."); return -EIO; } if (buf[6] != 0x10) { err("boot bad boot pattern 10."); return -EIO; } for (i = 4; i <= 6; i++) checksum += buf[i]; if (buf[7] * 256 + buf[8] != checksum) { err("boot bad boot checksum."); return -EIO; } break; } return 0;}int af9005_download_firmware(struct usb_device *udev, const struct firmware *fw){ int i, packets, ret, act_len; u8 buf[FW_BULKOUT_SIZE + 2]; u8 reply; ret = af9005_boot_packet(udev, FW_CONFIG, &reply); if (ret) return ret; if (reply != 0x01) { err("before downloading firmware, FW_CONFIG expected 0x01, received 0x%x", reply); return -EIO; } packets = fw->size / FW_BULKOUT_SIZE; buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff); buf[1] = (u8) ((FW_BULKOUT_SIZE >> 8) & 0xff); for (i = 0; i < packets; i++) { memcpy(&buf[2], fw->data + i * FW_BULKOUT_SIZE, FW_BULKOUT_SIZE); deb_fw(">>> "); debug_dump(buf, FW_BULKOUT_SIZE + 2, deb_fw); ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x02), buf, FW_BULKOUT_SIZE + 2, &act_len, 1000); if (ret) { err("firmware download failed at packet %d with code %d", i, ret); return ret; } } ret = af9005_boot_packet(udev, FW_CONFIRM, &reply); if (ret) return ret; if (reply != (u8) (packets & 0xff)) { err("after downloading firmware, FW_CONFIRM expected 0x%x, received 0x%x", packets & 0xff, reply); return -EIO; } ret = af9005_boot_packet(udev, FW_BOOT, &reply); if (ret) return ret; ret = af9005_boot_packet(udev, FW_CONFIG, &reply); if (ret) return ret; if (reply != 0x02) { err("after downloading firmware, FW_CONFIG expected 0x02, received 0x%x", reply); return -EIO; } return 0;}int af9005_led_control(struct dvb_usb_device *d, int onoff){ struct af9005_device_state *st = d->priv; int temp, ret; if (onoff && dvb_usb_af9005_led) temp = 1; else temp = 0; if (st->led_state != temp) { ret = af9005_write_register_bits(d, xd_p_reg_top_locken1, reg_top_locken1_pos, reg_top_locken1_len, temp); if (ret) return ret; ret = af9005_write_register_bits(d, xd_p_reg_top_lock1, reg_top_lock1_pos, reg_top_lock1_len, temp); if (ret) return ret; st->led_state = temp; } return 0;}static int af9005_frontend_attach(struct dvb_usb_adapter *adap){ u8 buf[8]; int i; /* without these calls the first commands after downloading the firmware fail. I put these calls here to simulate what it is done in dvb-usb-init.c. */ struct usb_device *udev = adap->dev->udev; usb_clear_halt(udev, usb_sndbulkpipe(udev, 2)); usb_clear_halt(udev, usb_rcvbulkpipe(udev, 1)); if (dvb_usb_af9005_dump_eeprom) { printk("EEPROM DUMP\n"); for (i = 0; i < 255; i += 8) { af9005_read_eeprom(adap->dev, i, buf, 8); printk("ADDR %x ", i); debug_dump(buf, 8, printk); } } adap->fe = af9005_fe_attach(adap->dev); return 0;}static int af9005_rc_query(struct dvb_usb_device *d, u32 * event, int *state){ struct af9005_device_state *st = d->priv; int ret, len; u8 obuf[5]; u8 ibuf[256]; *state = REMOTE_NO_KEY_PRESSED; if (rc_decode == NULL) { /* it shouldn't never come here */ return 0; } /* deb_info("rc_query\n"); */ obuf[0] = 3; /* rest of packet length low */ obuf[1] = 0; /* rest of packet lentgh high */ obuf[2] = 0x40; /* read remote */ obuf[3] = 1; /* rest of packet length */ obuf[4] = st->sequence++; /* sequence number */ ret = af9005_usb_generic_rw(d, obuf, 5, ibuf, 256, 0); if (ret) { err("rc query failed"); return ret; } if (ibuf[2] != 0x41) { err("rc query bad header."); return -EIO; } if (ibuf[4] != obuf[4]) { err("rc query bad sequence."); return -EIO; } len = ibuf[5]; if (len > 246) { err("rc query invalid length"); return -EIO; } if (len > 0) { deb_rc("rc data (%d) ", len); debug_dump((ibuf + 6), len, deb_rc); ret = rc_decode(d, &ibuf[6], len, event, state); if (ret) { err("rc_decode failed"); return ret; } else { deb_rc("rc_decode state %x event %x\n", *state, *event); if (*state == REMOTE_KEY_REPEAT) *event = d->last_event; } } return 0;}static int af9005_power_ctrl(struct dvb_usb_device *d, int onoff){ return 0;}static int af9005_pid_filter_control(struct dvb_usb_adapter *adap, int onoff){ int ret; deb_info("pid filter control onoff %d\n", onoff); if (onoff) { ret = af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 1); if (ret) return ret; ret = af9005_write_register_bits(adap->dev, XD_MP2IF_DMX_CTRL, 1, 1, 1); if (ret) return ret; ret = af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 1); } else ret = af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 0); if (ret) return ret; deb_info("pid filter control ok\n"); return 0;}static int af9005_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff){ u8 cmd = index & 0x1f; int ret; deb_info("set pid filter, index %d, pid %x, onoff %d\n", index, pid, onoff); if (onoff) { /* cannot use it as pid_filter_ctrl since it has to be done before setting the first pid */ if (adap->feedcount == 1) { deb_info("first pid set, enable pid table\n"); ret = af9005_pid_filter_control(adap, onoff); if (ret) return ret; } ret = af9005_write_ofdm_register(adap->dev, XD_MP2IF_PID_DATA_L, (u8) (pid & 0xff)); if (ret) return ret; ret = af9005_write_ofdm_register(adap->dev, XD_MP2IF_PID_DATA_H, (u8) (pid >> 8)); if (ret) return ret; cmd |= 0x20 | 0x40; } else { if (adap->feedcount == 0) { deb_info("last pid unset, disable pid table\n"); ret = af9005_pid_filter_control(adap, onoff); if (ret) return ret; } } ret = af9005_write_ofdm_register(adap->dev, XD_MP2IF_PID_IDX, cmd); if (ret) return ret; deb_info("set pid ok\n"); return 0;}static int af9005_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props, struct dvb_usb_device_description **desc, int *cold){ int ret; u8 reply; ret = af9005_boot_packet(udev, FW_CONFIG, &reply); if (ret) return ret; deb_info("result of FW_CONFIG in identify state %d\n", reply); if (reply == 0x01) *cold = 1; else if (reply == 0x02) *cold = 0; else return -EIO; deb_info("Identify state cold = %d\n", *cold); return 0;}static struct dvb_usb_device_properties af9005_properties;static int af9005_usb_probe(struct usb_interface *intf, const struct usb_device_id *id){ return dvb_usb_device_init(intf, &af9005_properties, THIS_MODULE, NULL);}static struct usb_device_id af9005_usb_table[] = { {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9005)}, {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE)}, {0},};MODULE_DEVICE_TABLE(usb, af9005_usb_table);static struct dvb_usb_device_properties af9005_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = DEVICE_SPECIFIC, .firmware = "af9005.fw", .download_firmware = af9005_download_firmware, .no_reconnect = 1, .size_of_priv = sizeof(struct af9005_device_state), .num_adapters = 1, .adapter = { { .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, .pid_filter = af9005_pid_filter, /* .pid_filter_ctrl = af9005_pid_filter_control, */ .frontend_attach = af9005_frontend_attach, /* .tuner_attach = af9005_tuner_attach, */ /* parameter for the MPEG2-data transfer */ .stream = { .type = USB_BULK, .count = 10, .endpoint = 0x04, .u = { .bulk = { .buffersize = 4096, /* actual size seen is 3948 */ } } }, } }, .power_ctrl = af9005_power_ctrl, .identify_state = af9005_identify_state, .i2c_algo = &af9005_i2c_algo, .rc_interval = 200, .rc_key_map = NULL, .rc_key_map_size = 0, .rc_query = af9005_rc_query, .num_device_descs = 2, .devices = { {.name = "Afatech DVB-T USB1.1 stick", .cold_ids = {&af9005_usb_table[0], NULL}, .warm_ids = {NULL}, }, {.name = "TerraTec Cinergy T USB XE", .cold_ids = {&af9005_usb_table[1], NULL}, .warm_ids = {NULL}, }, {NULL}, }};/* usb specific object needed to register this driver with the usb subsystem */static struct usb_driver af9005_usb_driver = { .name = "dvb_usb_af9005", .probe = af9005_usb_probe, .disconnect = dvb_usb_device_exit, .id_table = af9005_usb_table,};/* module stuff */static int __init af9005_usb_module_init(void){ int result; if ((result = usb_register(&af9005_usb_driver))) { err("usb_register failed. (%d)", result); return result; } rc_decode = symbol_request(af9005_rc_decode); rc_keys = symbol_request(af9005_rc_keys); rc_keys_size = symbol_request(af9005_rc_keys_size); if (rc_decode == NULL || rc_keys == NULL || rc_keys_size == NULL) { err("af9005_rc_decode function not found, disabling remote"); af9005_properties.rc_query = NULL; } else { af9005_properties.rc_key_map = rc_keys; af9005_properties.rc_key_map_size = *rc_keys_size; } return 0;}static void __exit af9005_usb_module_exit(void){ /* release rc decode symbols */ if (rc_decode != NULL) symbol_put(af9005_rc_decode); if (rc_keys != NULL) symbol_put(af9005_rc_keys); if (rc_keys_size != NULL) symbol_put(af9005_rc_keys_size); /* deregister this driver from the USB subsystem */ usb_deregister(&af9005_usb_driver);}module_init(af9005_usb_module_init);module_exit(af9005_usb_module_exit);MODULE_AUTHOR("Luca Olivetti <luca@ventoso.org>");MODULE_DESCRIPTION("Driver for Afatech 9005 DVB-T USB1.1 stick");MODULE_VERSION("1.0");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -