/*
* driver for Earthsoft PT1
*
* Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info>
*
* based on pt1dvr - http://pt1dvr.sourceforge.jp/
* by Tomoaki Ishikawa <tomy@users.sourceforge.jp>
*
* 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 <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/pci.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
#include "dvbdev.h"
#include "dvb_demux.h"
#include "dmxdev.h"
#include "dvb_net.h"
#include "dvb_frontend.h"
#include "va1j5jf8007t.h"
#include "va1j5jf8007s.h"
#define DRIVER_NAME "earth-pt1"
#define PT1_PAGE_SHIFT 12
#define PT1_PAGE_SIZE (1 << PT1_PAGE_SHIFT)
#define PT1_NR_UPACKETS 1024
#define PT1_NR_BUFS 511
struct pt1_buffer_page {
__le32 upackets[PT1_NR_UPACKETS];
};
struct pt1_table_page {
__le32 next_pfn;
__le32 buf_pfns[PT1_NR_BUFS];
};
struct pt1_buffer {
struct pt1_buffer_page *page;
dma_addr_t addr;
};
struct pt1_table {
struct pt1_table_page *page;
dma_addr_t addr;
struct pt1_buffer bufs[PT1_NR_BUFS];
};
#define PT1_NR_ADAPS 4
struct pt1_adapter;
struct pt1 {
struct pci_dev *pdev;
void __iomem *regs;
struct i2c_adapter i2c_adap;
int i2c_running;
struct pt1_adapter *adaps[PT1_NR_ADAPS];
struct pt1_table *tables;
struct task_struct *kthread;
};
struct pt1_adapter {
struct pt1 *pt1;
int index;
u8 *buf;
int upacket_count;
int packet_count;
struct dvb_adapter adap;
struct dvb_demux demux;
int users;
struct dmxdev dmxdev;
struct dvb_net net;
struct dvb_frontend *fe;
int (*orig_set_voltage)(struct dvb_frontend *fe,
fe_sec_voltage_t voltage);
};
#define pt1_printk(level, pt1, format, arg...) \
dev_printk(level, &(pt1)->pdev->dev, format, ##arg)
static void pt1_write_reg(struct pt1 *pt1, int reg, u32 data)
{
writel(data, pt1->regs + reg * 4);
}
static u32 pt1_read_reg(struct pt1 *pt1, int reg)
{
return readl(pt1->regs + reg * 4);
}
static int pt1_nr_tables = 64;
module_param_named(nr_tables, pt1_nr_tables, int, 0);
static void pt1_increment_table_count(struct pt1 *pt1)
{
pt1_write_reg(pt1, 0, 0x00000020);
}
static void pt1_init_table_count(struct pt1 *pt1)
{
pt1_write_reg(pt1, 0, 0x00000010);
}
static void pt1_register_tables(struct pt1 *pt1, u32 first_pfn)
{
pt1_write_reg(pt1, 5, first_pfn);
pt1_write_reg(pt1, 0, 0x0c000040);
}
static void pt1_unregister_tables(struct pt1 *pt1)
{
pt1_write_reg(pt1, 0, 0x08080000);
}
static int pt1_sync(struct pt1 *pt1)
{
int i;
for (i = 0; i < 57; i++) {
if (pt1_read_reg(pt1, 0) & 0x20000000)
return 0;
pt1_write_reg(pt1, 0, 0x00000008);
}
pt1_printk(KERN_ERR, pt1, "could not sync\n");
return -EIO;
}
static u64 pt1_identify(struct pt1 *pt1)
{
int i;
u64 id;
id = 0;
for (i = 0; i < 57; i++) {
id |= (u64)(pt1_read_reg(pt1, 0) >> 30 & 1) << i;
pt1_write_reg(pt1, 0, 0x00000008);
}
return id;
}
static int