#include <asm/semaphore.h>
#include <linux/list.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/usb.h>
-#include <linux/version.h>
#include <linux/interrupt.h>
#include <linux/firmware.h>
+#if defined(CONFIG_CRC32) || defined(CONFIG_CRC32_MODULE)
#include <linux/crc32.h>
+#else
+#warning "CRC checking of firmware not available"
+#endif
#include <linux/init.h>
#include "dmxdev.h"
#include "dvb_demux.h"
+#include "dvb_i2c.h"
#include "dvb_filter.h"
#include "dvb_frontend.h"
#include "dvb_net.h"
-#include "ttusbdecfe.h"
-static int debug;
-static int output_pva;
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
-module_param(output_pva, int, 0444);
-MODULE_PARM_DESC(output_pva, "Output PVA from dvr device (default:off)");
+static int debug = 0;
+static int output_pva = 0;
#define dprintk if (debug) printk
#define MAX_PVA_LENGTH 6144
+#define LOF_HI 10600000
+#define LOF_LO 9750000
+
enum ttusb_dec_model {
TTUSB_DEC2000T,
TTUSB_DEC2540T,
struct dmxdev dmxdev;
struct dvb_demux demux;
struct dmx_frontend frontend;
+ struct dvb_i2c_bus i2c_bus;
struct dvb_net dvb_net;
- struct dvb_frontend* fe;
+ struct dvb_frontend_info *frontend_info;
+ int (*frontend_ioctl) (struct dvb_frontend *, unsigned int, void *);
u16 pid[DMX_PES_OTHER];
+ int hi_band;
+ int voltage;
/* USB bits */
struct usb_device *udev;
struct list_head filter_info_list;
};
+static struct dvb_frontend_info dec2000t_frontend_info = {
+ .name = "TechnoTrend/Hauppauge DEC2000-t Frontend",
+ .type = FE_OFDM,
+ .frequency_min = 51000000,
+ .frequency_max = 858000000,
+ .frequency_stepsize = 62500,
+ .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_HIERARCHY_AUTO,
+};
+
+static struct dvb_frontend_info dec3000s_frontend_info = {
+ .name = "TechnoTrend/Hauppauge DEC3000-s Frontend",
+ .type = FE_QPSK,
+ .frequency_min = 950000,
+ .frequency_max = 2150000,
+ .frequency_stepsize = 125,
+ .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_HIERARCHY_AUTO,
+};
+
static void ttusb_dec_set_model(struct ttusb_dec *dec,
enum ttusb_dec_model model);
&dec->iso_dma_handle);
memset(dec->iso_buffer, 0,
- ISO_FRAME_SIZE * (FRAMES_PER_ISO_BUF * ISO_BUF_COUNT));
+ sizeof(ISO_FRAME_SIZE * (FRAMES_PER_ISO_BUF * ISO_BUF_COUNT)));
for (i = 0; i < ISO_BUF_COUNT; i++) {
struct urb *urb;
u16 firmware_csum = 0;
u16 firmware_csum_ns;
u32 firmware_size_nl;
+#if defined(CONFIG_CRC32) || defined(CONFIG_CRC32_MODULE)
u32 crc32_csum, crc32_check, tmp;
+#endif
const struct firmware *fw_entry = NULL;
-
dprintk("%s\n", __FUNCTION__);
if (request_firmware(&fw_entry, dec->firmware_name, &dec->udev->dev)) {
/* a 32 bit checksum over the first 56 bytes of the DSP Code is stored
at offset 56 of file, so use it to check if the firmware file is
valid. */
+#if defined(CONFIG_CRC32) || defined(CONFIG_CRC32_MODULE)
crc32_csum = crc32(~0L, firmware, 56) ^ ~0L;
memcpy(&tmp, &firmware[56], 4);
crc32_check = htonl(tmp);
__FUNCTION__, crc32_csum, crc32_check);
return -1;
}
+#endif
memcpy(idstring, &firmware[36], 20);
idstring[20] = '\0';
printk(KERN_INFO "ttusb_dec: found DSP code \"%s\".\n", idstring);
ttusb_dec_set_model(dec, TTUSB_DEC3000S);
break;
case 0x00070009:
- case 0x00070013:
ttusb_dec_set_model(dec, TTUSB_DEC2000T);
break;
case 0x00070011:
dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend);
dvb_dmxdev_release(&dec->dmxdev);
dvb_dmx_release(&dec->demux);
- if (dec->fe) dvb_unregister_frontend(dec->fe);
dvb_unregister_adapter(dec->adapter);
}
}
}
+static int ttusb_dec_2000t_frontend_ioctl(struct dvb_frontend *fe, unsigned int cmd,
+ void *arg)
+{
+ struct ttusb_dec *dec = fe->data;
+
+ dprintk("%s\n", __FUNCTION__);
+
+ switch (cmd) {
+
+ case FE_GET_INFO:
+ dprintk("%s: FE_GET_INFO\n", __FUNCTION__);
+ memcpy(arg, dec->frontend_info,
+ sizeof (struct dvb_frontend_info));
+ break;
+
+ case FE_READ_STATUS: {
+ fe_status_t *status = (fe_status_t *)arg;
+ dprintk("%s: FE_READ_STATUS\n", __FUNCTION__);
+ *status = FE_HAS_SIGNAL | FE_HAS_VITERBI |
+ FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK;
+ break;
+ }
+
+ case FE_READ_BER: {
+ u32 *ber = (u32 *)arg;
+ dprintk("%s: FE_READ_BER\n", __FUNCTION__);
+ *ber = 0;
+ return -ENOSYS;
+ break;
+ }
+
+ case FE_READ_SIGNAL_STRENGTH: {
+ dprintk("%s: FE_READ_SIGNAL_STRENGTH\n", __FUNCTION__);
+ *(s32 *)arg = 0xFF;
+ return -ENOSYS;
+ break;
+ }
+
+ case FE_READ_SNR:
+ dprintk("%s: FE_READ_SNR\n", __FUNCTION__);
+ *(s32 *)arg = 0;
+ return -ENOSYS;
+ break;
+
+ case FE_READ_UNCORRECTED_BLOCKS:
+ dprintk("%s: FE_READ_UNCORRECTED_BLOCKS\n", __FUNCTION__);
+ *(u32 *)arg = 0;
+ return -ENOSYS;
+ break;
+
+ case FE_SET_FRONTEND: {
+ struct dvb_frontend_parameters *p =
+ (struct dvb_frontend_parameters *)arg;
+ u8 b[] = { 0x00, 0x00, 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0xff };
+ u32 freq;
+
+ dprintk("%s: FE_SET_FRONTEND\n", __FUNCTION__);
+
+ dprintk(" frequency->%d\n", p->frequency);
+ dprintk(" symbol_rate->%d\n",
+ p->u.qam.symbol_rate);
+ dprintk(" inversion->%d\n", p->inversion);
+
+ freq = htonl(p->frequency / 1000);
+ memcpy(&b[4], &freq, sizeof (u32));
+ ttusb_dec_send_command(dec, 0x71, sizeof(b), b, NULL, NULL);
+
+ break;
+ }
+
+ case FE_GET_FRONTEND:
+ dprintk("%s: FE_GET_FRONTEND\n", __FUNCTION__);
+ break;
+
+ case FE_SLEEP:
+ dprintk("%s: FE_SLEEP\n", __FUNCTION__);
+ return -ENOSYS;
+ break;
+
+ case FE_INIT:
+ dprintk("%s: FE_INIT\n", __FUNCTION__);
+ break;
+
+ default:
+ dprintk("%s: unknown IOCTL (0x%X)\n", __FUNCTION__, cmd);
+ return -EINVAL;
+
+ }
+
+ return 0;
+}
+
+static int ttusb_dec_3000s_frontend_ioctl(struct dvb_frontend *fe,
+ unsigned int cmd, void *arg)
+{
+ struct ttusb_dec *dec = fe->data;
+
+ dprintk("%s\n", __FUNCTION__);
+
+ switch (cmd) {
+
+ case FE_GET_INFO:
+ dprintk("%s: FE_GET_INFO\n", __FUNCTION__);
+ memcpy(arg, dec->frontend_info,
+ sizeof (struct dvb_frontend_info));
+ break;
+
+ case FE_READ_STATUS: {
+ fe_status_t *status = (fe_status_t *)arg;
+ dprintk("%s: FE_READ_STATUS\n", __FUNCTION__);
+ *status = FE_HAS_SIGNAL | FE_HAS_VITERBI |
+ FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK;
+ break;
+ }
+
+ case FE_READ_BER: {
+ u32 *ber = (u32 *)arg;
+ dprintk("%s: FE_READ_BER\n", __FUNCTION__);
+ *ber = 0;
+ return -ENOSYS;
+ break;
+ }
+
+ case FE_READ_SIGNAL_STRENGTH: {
+ dprintk("%s: FE_READ_SIGNAL_STRENGTH\n", __FUNCTION__);
+ *(s32 *)arg = 0xFF;
+ return -ENOSYS;
+ break;
+ }
+
+ case FE_READ_SNR:
+ dprintk("%s: FE_READ_SNR\n", __FUNCTION__);
+ *(s32 *)arg = 0;
+ return -ENOSYS;
+ break;
+
+ case FE_READ_UNCORRECTED_BLOCKS:
+ dprintk("%s: FE_READ_UNCORRECTED_BLOCKS\n", __FUNCTION__);
+ *(u32 *)arg = 0;
+ return -ENOSYS;
+ break;
+
+ case FE_SET_FRONTEND: {
+ struct dvb_frontend_parameters *p =
+ (struct dvb_frontend_parameters *)arg;
+ u8 b[] = { 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00 };
+ u32 freq;
+ u32 sym_rate;
+ u32 band;
+ u32 lnb_voltage;
+
+ dprintk("%s: FE_SET_FRONTEND\n", __FUNCTION__);
+
+ dprintk(" frequency->%d\n", p->frequency);
+ dprintk(" symbol_rate->%d\n",
+ p->u.qam.symbol_rate);
+ dprintk(" inversion->%d\n", p->inversion);
+
+ freq = htonl(p->frequency * 1000 +
+ (dec->hi_band ? LOF_HI : LOF_LO));
+ memcpy(&b[4], &freq, sizeof(u32));
+ sym_rate = htonl(p->u.qam.symbol_rate);
+ memcpy(&b[12], &sym_rate, sizeof(u32));
+ band = htonl(dec->hi_band ? LOF_HI : LOF_LO);
+ memcpy(&b[24], &band, sizeof(u32));
+ lnb_voltage = htonl(dec->voltage);
+ memcpy(&b[28], &lnb_voltage, sizeof(u32));
+
+ ttusb_dec_send_command(dec, 0x71, sizeof(b), b, NULL, NULL);
+
+ break;
+ }
+
+ case FE_GET_FRONTEND:
+ dprintk("%s: FE_GET_FRONTEND\n", __FUNCTION__);
+ break;
+
+ case FE_SLEEP:
+ dprintk("%s: FE_SLEEP\n", __FUNCTION__);
+ return -ENOSYS;
+ break;
+
+ case FE_INIT:
+ dprintk("%s: FE_INIT\n", __FUNCTION__);
+ break;
+
+ case FE_DISEQC_SEND_MASTER_CMD:
+ dprintk("%s: FE_DISEQC_SEND_MASTER_CMD\n", __FUNCTION__);
+ break;
+
+ case FE_DISEQC_SEND_BURST:
+ dprintk("%s: FE_DISEQC_SEND_BURST\n", __FUNCTION__);
+ break;
+
+ case FE_SET_TONE: {
+ fe_sec_tone_mode_t tone = (fe_sec_tone_mode_t)arg;
+ dprintk("%s: FE_SET_TONE\n", __FUNCTION__);
+ dec->hi_band = (SEC_TONE_ON == tone);
+ break;
+ }
+
+ case FE_SET_VOLTAGE:
+ dprintk("%s: FE_SET_VOLTAGE\n", __FUNCTION__);
+ switch ((fe_sec_voltage_t) arg) {
+ case SEC_VOLTAGE_13:
+ dec->voltage = 13;
+ break;
+ case SEC_VOLTAGE_18:
+ dec->voltage = 18;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ break;
+
+ default:
+ dprintk("%s: unknown IOCTL (0x%X)\n", __FUNCTION__, cmd);
+ return -EINVAL;
+
+ }
+
+ return 0;
+}
+
+static void ttusb_dec_init_frontend(struct ttusb_dec *dec)
+{
+ dec->i2c_bus.adapter = dec->adapter;
+
+ dvb_register_frontend(dec->frontend_ioctl, &dec->i2c_bus, (void *)dec,
+ dec->frontend_info);
+}
+
+static void ttusb_dec_exit_frontend(struct ttusb_dec *dec)
+{
+ dvb_unregister_frontend(dec->frontend_ioctl, &dec->i2c_bus);
+}
+
static void ttusb_dec_init_filters(struct ttusb_dec *dec)
{
INIT_LIST_HEAD(&dec->filter_info_list);
}
}
-int fe_send_command(struct dvb_frontend* fe, const u8 command,
- int param_length, const u8 params[],
- int *result_length, u8 cmd_result[])
-{
- struct ttusb_dec* dec = (struct ttusb_dec*) fe->dvb->priv;
- return ttusb_dec_send_command(dec, command, param_length, params, result_length, cmd_result);
-}
-
-struct ttusbdecfe_config fe_config = {
- .send_command = fe_send_command
-};
-
static int ttusb_dec_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
return 0;
}
ttusb_dec_init_dvb(dec);
-
- dec->adapter->priv = dec;
- switch (id->idProduct) {
- case 0x1006:
- dec->fe = ttusbdecfe_dvbs_attach(&fe_config);
- break;
-
- case 0x1008:
- case 0x1009:
- dec->fe = ttusbdecfe_dvbt_attach(&fe_config);
- break;
- }
-
- if (dec->fe == NULL) {
- printk("dvb-ttusb-dec: A frontend driver was not found for device %04x/%04x\n",
- dec->udev->descriptor.idVendor,
- dec->udev->descriptor.idProduct);
- } else {
- if (dvb_register_frontend(dec->adapter, dec->fe)) {
- printk("budget-ci: Frontend registration failed!\n");
- if (dec->fe->ops->release)
- dec->fe->ops->release(dec->fe);
- dec->fe = NULL;
- }
- }
-
+ ttusb_dec_init_frontend(dec);
ttusb_dec_init_v_pes(dec);
ttusb_dec_init_filters(dec);
ttusb_dec_init_tasklet(dec);
ttusb_dec_exit_tasklet(dec);
ttusb_dec_exit_filters(dec);
ttusb_dec_exit_usb(dec);
+ ttusb_dec_exit_frontend(dec);
ttusb_dec_exit_dvb(dec);
}
case TTUSB_DEC2000T:
dec->model_name = "DEC2000-t";
dec->firmware_name = "dvb-ttusb-dec-2000t.fw";
+ dec->frontend_info = &dec2000t_frontend_info;
+ dec->frontend_ioctl = ttusb_dec_2000t_frontend_ioctl;
break;
case TTUSB_DEC2540T:
dec->model_name = "DEC2540-t";
dec->firmware_name = "dvb-ttusb-dec-2540t.fw";
+ dec->frontend_info = &dec2000t_frontend_info;
+ dec->frontend_ioctl = ttusb_dec_2000t_frontend_ioctl;
break;
case TTUSB_DEC3000S:
dec->model_name = "DEC3000-s";
dec->firmware_name = "dvb-ttusb-dec-3000s.fw";
+ dec->frontend_info = &dec3000s_frontend_info;
+ dec->frontend_ioctl = ttusb_dec_3000s_frontend_ioctl;
break;
}
}
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(usb, ttusb_dec_table);
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug level");
+MODULE_PARM(output_pva, "i");
+MODULE_PARM_DESC(output_pva, "Output PVA from dvr device");