mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-24 10:37:45 +07:00
0df289a209
The DVB API was originally defined using typedefs. This is against Kernel CodingStyle, and there's no good usage here. While we can't remove its usage on userspace, we can avoid its usage in Kernelspace. So, let's do it. This patch was generated by this shell script: for j in $(grep typedef include/uapi/linux/dvb/frontend.h |cut -d' ' -f 3); do for i in $(find drivers/media -name '*.[ch]' -type f) $(find drivers/staging/media -name '*.[ch]' -type f); do sed "s,${j}_t,enum $j," <$i >a && mv a $i; done; done While here, make CodingStyle fixes on the affected lines. Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com> Acked-by: Stefan Richter <stefanr@s5r6.in-berlin.de> # for drivers/media/firewire/*
585 lines
14 KiB
C
585 lines
14 KiB
C
/* DVB USB framework compliant Linux driver for the Opera1 DVB-S Card
|
|
*
|
|
* Copyright (C) 2006 Mario Hlawitschka (dh1pa@amsat.org)
|
|
* Copyright (C) 2006 Marco Gittler (g.marco@freenet.de)
|
|
*
|
|
* 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, version 2.
|
|
*
|
|
* see Documentation/dvb/README.dvb-usb for more information
|
|
*/
|
|
|
|
#define DVB_USB_LOG_PREFIX "opera"
|
|
|
|
#include "dvb-usb.h"
|
|
#include "stv0299.h"
|
|
|
|
#define OPERA_READ_MSG 0
|
|
#define OPERA_WRITE_MSG 1
|
|
#define OPERA_I2C_TUNER 0xd1
|
|
|
|
#define READ_FX2_REG_REQ 0xba
|
|
#define READ_MAC_ADDR 0x08
|
|
#define OPERA_WRITE_FX2 0xbb
|
|
#define OPERA_TUNER_REQ 0xb1
|
|
#define REG_1F_SYMBOLRATE_BYTE0 0x1f
|
|
#define REG_20_SYMBOLRATE_BYTE1 0x20
|
|
#define REG_21_SYMBOLRATE_BYTE2 0x21
|
|
|
|
#define ADDR_B600_VOLTAGE_13V (0x02)
|
|
#define ADDR_B601_VOLTAGE_18V (0x03)
|
|
#define ADDR_B1A6_STREAM_CTRL (0x04)
|
|
#define ADDR_B880_READ_REMOTE (0x05)
|
|
|
|
struct opera1_state {
|
|
u32 last_key_pressed;
|
|
};
|
|
struct rc_map_opera_table {
|
|
u32 keycode;
|
|
u32 event;
|
|
};
|
|
|
|
static int dvb_usb_opera1_debug;
|
|
module_param_named(debug, dvb_usb_opera1_debug, int, 0644);
|
|
MODULE_PARM_DESC(debug,
|
|
"set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64 (or-able))."
|
|
DVB_USB_DEBUG_STATUS);
|
|
|
|
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
|
|
|
|
|
static int opera1_xilinx_rw(struct usb_device *dev, u8 request, u16 value,
|
|
u8 * data, u16 len, int flags)
|
|
{
|
|
int ret;
|
|
u8 tmp;
|
|
u8 *buf;
|
|
unsigned int pipe = (flags == OPERA_READ_MSG) ?
|
|
usb_rcvctrlpipe(dev,0) : usb_sndctrlpipe(dev, 0);
|
|
u8 request_type = (flags == OPERA_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT;
|
|
|
|
buf = kmalloc(len, GFP_KERNEL);
|
|
if (!buf)
|
|
return -ENOMEM;
|
|
|
|
if (flags == OPERA_WRITE_MSG)
|
|
memcpy(buf, data, len);
|
|
ret = usb_control_msg(dev, pipe, request,
|
|
request_type | USB_TYPE_VENDOR, value, 0x0,
|
|
buf, len, 2000);
|
|
|
|
if (request == OPERA_TUNER_REQ) {
|
|
tmp = buf[0];
|
|
if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
|
|
OPERA_TUNER_REQ, USB_DIR_IN | USB_TYPE_VENDOR,
|
|
0x01, 0x0, buf, 1, 2000) < 1 || buf[0] != 0x08) {
|
|
ret = 0;
|
|
goto out;
|
|
}
|
|
buf[0] = tmp;
|
|
}
|
|
if (flags == OPERA_READ_MSG)
|
|
memcpy(data, buf, len);
|
|
out:
|
|
kfree(buf);
|
|
return ret;
|
|
}
|
|
|
|
/* I2C */
|
|
|
|
static int opera1_usb_i2c_msgxfer(struct dvb_usb_device *dev, u16 addr,
|
|
u8 * buf, u16 len)
|
|
{
|
|
int ret = 0;
|
|
u8 request;
|
|
u16 value;
|
|
|
|
if (!dev) {
|
|
info("no usb_device");
|
|
return -EINVAL;
|
|
}
|
|
if (mutex_lock_interruptible(&dev->usb_mutex) < 0)
|
|
return -EAGAIN;
|
|
|
|
switch (addr>>1){
|
|
case ADDR_B600_VOLTAGE_13V:
|
|
request=0xb6;
|
|
value=0x00;
|
|
break;
|
|
case ADDR_B601_VOLTAGE_18V:
|
|
request=0xb6;
|
|
value=0x01;
|
|
break;
|
|
case ADDR_B1A6_STREAM_CTRL:
|
|
request=0xb1;
|
|
value=0xa6;
|
|
break;
|
|
case ADDR_B880_READ_REMOTE:
|
|
request=0xb8;
|
|
value=0x80;
|
|
break;
|
|
default:
|
|
request=0xb1;
|
|
value=addr;
|
|
}
|
|
ret = opera1_xilinx_rw(dev->udev, request,
|
|
value, buf, len,
|
|
addr&0x01?OPERA_READ_MSG:OPERA_WRITE_MSG);
|
|
|
|
mutex_unlock(&dev->usb_mutex);
|
|
return ret;
|
|
}
|
|
|
|
static int opera1_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
|
int num)
|
|
{
|
|
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
|
int i = 0, tmp = 0;
|
|
|
|
if (!d)
|
|
return -ENODEV;
|
|
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
|
return -EAGAIN;
|
|
|
|
for (i = 0; i < num; i++) {
|
|
if ((tmp = opera1_usb_i2c_msgxfer(d,
|
|
(msg[i].addr<<1)|(msg[i].flags&I2C_M_RD?0x01:0),
|
|
msg[i].buf,
|
|
msg[i].len
|
|
)) != msg[i].len) {
|
|
break;
|
|
}
|
|
if (dvb_usb_opera1_debug & 0x10)
|
|
info("sending i2c message %d %d", tmp, msg[i].len);
|
|
}
|
|
mutex_unlock(&d->i2c_mutex);
|
|
return num;
|
|
}
|
|
|
|
static u32 opera1_i2c_func(struct i2c_adapter *adapter)
|
|
{
|
|
return I2C_FUNC_I2C;
|
|
}
|
|
|
|
static struct i2c_algorithm opera1_i2c_algo = {
|
|
.master_xfer = opera1_i2c_xfer,
|
|
.functionality = opera1_i2c_func,
|
|
};
|
|
|
|
static int opera1_set_voltage(struct dvb_frontend *fe,
|
|
enum fe_sec_voltage voltage)
|
|
{
|
|
static u8 command_13v[1]={0x00};
|
|
static u8 command_18v[1]={0x01};
|
|
struct i2c_msg msg[] = {
|
|
{.addr = ADDR_B600_VOLTAGE_13V,.flags = 0,.buf = command_13v,.len = 1},
|
|
};
|
|
struct dvb_usb_adapter *udev_adap =
|
|
(struct dvb_usb_adapter *)(fe->dvb->priv);
|
|
if (voltage == SEC_VOLTAGE_18) {
|
|
msg[0].addr = ADDR_B601_VOLTAGE_18V;
|
|
msg[0].buf = command_18v;
|
|
}
|
|
i2c_transfer(&udev_adap->dev->i2c_adap, msg, 1);
|
|
return 0;
|
|
}
|
|
|
|
static int opera1_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate,
|
|
u32 ratio)
|
|
{
|
|
stv0299_writereg(fe, 0x13, 0x98);
|
|
stv0299_writereg(fe, 0x14, 0x95);
|
|
stv0299_writereg(fe, REG_1F_SYMBOLRATE_BYTE0, (ratio >> 16) & 0xff);
|
|
stv0299_writereg(fe, REG_20_SYMBOLRATE_BYTE1, (ratio >> 8) & 0xff);
|
|
stv0299_writereg(fe, REG_21_SYMBOLRATE_BYTE2, (ratio) & 0xf0);
|
|
return 0;
|
|
|
|
}
|
|
static u8 opera1_inittab[] = {
|
|
0x00, 0xa1,
|
|
0x01, 0x15,
|
|
0x02, 0x30,
|
|
0x03, 0x00,
|
|
0x04, 0x7d,
|
|
0x05, 0x05,
|
|
0x06, 0x02,
|
|
0x07, 0x00,
|
|
0x0b, 0x00,
|
|
0x0c, 0x01,
|
|
0x0d, 0x81,
|
|
0x0e, 0x44,
|
|
0x0f, 0x19,
|
|
0x10, 0x3f,
|
|
0x11, 0x84,
|
|
0x12, 0xda,
|
|
0x13, 0x98,
|
|
0x14, 0x95,
|
|
0x15, 0xc9,
|
|
0x16, 0xeb,
|
|
0x17, 0x00,
|
|
0x18, 0x19,
|
|
0x19, 0x8b,
|
|
0x1a, 0x00,
|
|
0x1b, 0x82,
|
|
0x1c, 0x7f,
|
|
0x1d, 0x00,
|
|
0x1e, 0x00,
|
|
REG_1F_SYMBOLRATE_BYTE0, 0x06,
|
|
REG_20_SYMBOLRATE_BYTE1, 0x50,
|
|
REG_21_SYMBOLRATE_BYTE2, 0x10,
|
|
0x22, 0x00,
|
|
0x23, 0x00,
|
|
0x24, 0x37,
|
|
0x25, 0xbc,
|
|
0x26, 0x00,
|
|
0x27, 0x00,
|
|
0x28, 0x00,
|
|
0x29, 0x1e,
|
|
0x2a, 0x14,
|
|
0x2b, 0x1f,
|
|
0x2c, 0x09,
|
|
0x2d, 0x0a,
|
|
0x2e, 0x00,
|
|
0x2f, 0x00,
|
|
0x30, 0x00,
|
|
0x31, 0x1f,
|
|
0x32, 0x19,
|
|
0x33, 0xfc,
|
|
0x34, 0x13,
|
|
0xff, 0xff,
|
|
};
|
|
|
|
static struct stv0299_config opera1_stv0299_config = {
|
|
.demod_address = 0xd0>>1,
|
|
.min_delay_ms = 100,
|
|
.mclk = 88000000UL,
|
|
.invert = 1,
|
|
.skip_reinit = 0,
|
|
.lock_output = STV0299_LOCKOUTPUT_0,
|
|
.volt13_op0_op1 = STV0299_VOLT13_OP0,
|
|
.inittab = opera1_inittab,
|
|
.set_symbol_rate = opera1_stv0299_set_symbol_rate,
|
|
};
|
|
|
|
static int opera1_frontend_attach(struct dvb_usb_adapter *d)
|
|
{
|
|
d->fe_adap[0].fe = dvb_attach(stv0299_attach, &opera1_stv0299_config,
|
|
&d->dev->i2c_adap);
|
|
if ((d->fe_adap[0].fe) != NULL) {
|
|
d->fe_adap[0].fe->ops.set_voltage = opera1_set_voltage;
|
|
return 0;
|
|
}
|
|
info("not attached stv0299");
|
|
return -EIO;
|
|
}
|
|
|
|
static int opera1_tuner_attach(struct dvb_usb_adapter *adap)
|
|
{
|
|
dvb_attach(
|
|
dvb_pll_attach, adap->fe_adap[0].fe, 0xc0>>1,
|
|
&adap->dev->i2c_adap, DVB_PLL_OPERA1
|
|
);
|
|
return 0;
|
|
}
|
|
|
|
static int opera1_power_ctrl(struct dvb_usb_device *d, int onoff)
|
|
{
|
|
u8 val = onoff ? 0x01 : 0x00;
|
|
|
|
if (dvb_usb_opera1_debug)
|
|
info("power %s", onoff ? "on" : "off");
|
|
return opera1_xilinx_rw(d->udev, 0xb7, val,
|
|
&val, 1, OPERA_WRITE_MSG);
|
|
}
|
|
|
|
static int opera1_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
|
|
{
|
|
static u8 buf_start[2] = { 0xff, 0x03 };
|
|
static u8 buf_stop[2] = { 0xff, 0x00 };
|
|
struct i2c_msg start_tuner[] = {
|
|
{.addr = ADDR_B1A6_STREAM_CTRL,.buf = onoff ? buf_start : buf_stop,.len = 2},
|
|
};
|
|
if (dvb_usb_opera1_debug)
|
|
info("streaming %s", onoff ? "on" : "off");
|
|
i2c_transfer(&adap->dev->i2c_adap, start_tuner, 1);
|
|
return 0;
|
|
}
|
|
|
|
static int opera1_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
|
|
int onoff)
|
|
{
|
|
u8 b_pid[3];
|
|
struct i2c_msg msg[] = {
|
|
{.addr = ADDR_B1A6_STREAM_CTRL,.buf = b_pid,.len = 3},
|
|
};
|
|
if (dvb_usb_opera1_debug)
|
|
info("pidfilter index: %d pid: %d %s", index, pid,
|
|
onoff ? "on" : "off");
|
|
b_pid[0] = (2 * index) + 4;
|
|
b_pid[1] = onoff ? (pid & 0xff) : (0x00);
|
|
b_pid[2] = onoff ? ((pid >> 8) & 0xff) : (0x00);
|
|
i2c_transfer(&adap->dev->i2c_adap, msg, 1);
|
|
return 0;
|
|
}
|
|
|
|
static int opera1_pid_filter_control(struct dvb_usb_adapter *adap, int onoff)
|
|
{
|
|
int u = 0x04;
|
|
u8 b_pid[3];
|
|
struct i2c_msg msg[] = {
|
|
{.addr = ADDR_B1A6_STREAM_CTRL,.buf = b_pid,.len = 3},
|
|
};
|
|
if (dvb_usb_opera1_debug)
|
|
info("%s hw-pidfilter", onoff ? "enable" : "disable");
|
|
for (; u < 0x7e; u += 2) {
|
|
b_pid[0] = u;
|
|
b_pid[1] = 0;
|
|
b_pid[2] = 0x80;
|
|
i2c_transfer(&adap->dev->i2c_adap, msg, 1);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static struct rc_map_table rc_map_opera1_table[] = {
|
|
{0x5fa0, KEY_1},
|
|
{0x51af, KEY_2},
|
|
{0x5da2, KEY_3},
|
|
{0x41be, KEY_4},
|
|
{0x0bf5, KEY_5},
|
|
{0x43bd, KEY_6},
|
|
{0x47b8, KEY_7},
|
|
{0x49b6, KEY_8},
|
|
{0x05fa, KEY_9},
|
|
{0x45ba, KEY_0},
|
|
{0x09f6, KEY_CHANNELUP}, /*chanup */
|
|
{0x1be5, KEY_CHANNELDOWN}, /*chandown */
|
|
{0x5da3, KEY_VOLUMEDOWN}, /*voldown */
|
|
{0x5fa1, KEY_VOLUMEUP}, /*volup */
|
|
{0x07f8, KEY_SPACE}, /*tab */
|
|
{0x1fe1, KEY_OK}, /*play ok */
|
|
{0x1be4, KEY_ZOOM}, /*zoom */
|
|
{0x59a6, KEY_MUTE}, /*mute */
|
|
{0x5ba5, KEY_RADIO}, /*tv/f */
|
|
{0x19e7, KEY_RECORD}, /*rec */
|
|
{0x01fe, KEY_STOP}, /*Stop */
|
|
{0x03fd, KEY_PAUSE}, /*pause */
|
|
{0x03fc, KEY_SCREEN}, /*<- -> */
|
|
{0x07f9, KEY_CAMERA}, /*capture */
|
|
{0x47b9, KEY_ESC}, /*exit */
|
|
{0x43bc, KEY_POWER2}, /*power */
|
|
};
|
|
|
|
static int opera1_rc_query(struct dvb_usb_device *dev, u32 * event, int *state)
|
|
{
|
|
struct opera1_state *opst = dev->priv;
|
|
u8 rcbuffer[32];
|
|
const u16 startmarker1 = 0x10ed;
|
|
const u16 startmarker2 = 0x11ec;
|
|
struct i2c_msg read_remote[] = {
|
|
{.addr = ADDR_B880_READ_REMOTE,.buf = rcbuffer,.flags = I2C_M_RD,.len = 32},
|
|
};
|
|
int i = 0;
|
|
u32 send_key = 0;
|
|
|
|
if (i2c_transfer(&dev->i2c_adap, read_remote, 1) == 1) {
|
|
for (i = 0; i < 32; i++) {
|
|
if (rcbuffer[i])
|
|
send_key |= 1;
|
|
if (i < 31)
|
|
send_key = send_key << 1;
|
|
}
|
|
if (send_key & 0x8000)
|
|
send_key = (send_key << 1) | (send_key >> 15 & 0x01);
|
|
|
|
if (send_key == 0xffff && opst->last_key_pressed != 0) {
|
|
*state = REMOTE_KEY_REPEAT;
|
|
*event = opst->last_key_pressed;
|
|
return 0;
|
|
}
|
|
for (; send_key != 0;) {
|
|
if (send_key >> 16 == startmarker2) {
|
|
break;
|
|
} else if (send_key >> 16 == startmarker1) {
|
|
send_key =
|
|
(send_key & 0xfffeffff) | (startmarker1 << 16);
|
|
break;
|
|
} else
|
|
send_key >>= 1;
|
|
}
|
|
|
|
if (send_key == 0)
|
|
return 0;
|
|
|
|
send_key = (send_key & 0xffff) | 0x0100;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(rc_map_opera1_table); i++) {
|
|
if (rc5_scan(&rc_map_opera1_table[i]) == (send_key & 0xffff)) {
|
|
*state = REMOTE_KEY_PRESSED;
|
|
*event = rc_map_opera1_table[i].keycode;
|
|
opst->last_key_pressed =
|
|
rc_map_opera1_table[i].keycode;
|
|
break;
|
|
}
|
|
opst->last_key_pressed = 0;
|
|
}
|
|
} else
|
|
*state = REMOTE_NO_KEY_PRESSED;
|
|
return 0;
|
|
}
|
|
|
|
static struct usb_device_id opera1_table[] = {
|
|
{USB_DEVICE(USB_VID_CYPRESS, USB_PID_OPERA1_COLD)},
|
|
{USB_DEVICE(USB_VID_OPERA1, USB_PID_OPERA1_WARM)},
|
|
{}
|
|
};
|
|
|
|
MODULE_DEVICE_TABLE(usb, opera1_table);
|
|
|
|
static int opera1_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
|
|
{
|
|
u8 command[] = { READ_MAC_ADDR };
|
|
opera1_xilinx_rw(d->udev, 0xb1, 0xa0, command, 1, OPERA_WRITE_MSG);
|
|
opera1_xilinx_rw(d->udev, 0xb1, 0xa1, mac, 6, OPERA_READ_MSG);
|
|
return 0;
|
|
}
|
|
static int opera1_xilinx_load_firmware(struct usb_device *dev,
|
|
const char *filename)
|
|
{
|
|
const struct firmware *fw = NULL;
|
|
u8 *b, *p;
|
|
int ret = 0, i,fpgasize=40;
|
|
u8 testval;
|
|
info("start downloading fpga firmware %s",filename);
|
|
|
|
if ((ret = request_firmware(&fw, filename, &dev->dev)) != 0) {
|
|
err("did not find the firmware file. (%s) "
|
|
"Please see linux/Documentation/dvb/ for more details on firmware-problems.",
|
|
filename);
|
|
return ret;
|
|
} else {
|
|
p = kmalloc(fw->size, GFP_KERNEL);
|
|
opera1_xilinx_rw(dev, 0xbc, 0x00, &testval, 1, OPERA_READ_MSG);
|
|
if (p != NULL && testval != 0x67) {
|
|
|
|
u8 reset = 0, fpga_command = 0;
|
|
memcpy(p, fw->data, fw->size);
|
|
/* clear fpga ? */
|
|
opera1_xilinx_rw(dev, 0xbc, 0xaa, &fpga_command, 1,
|
|
OPERA_WRITE_MSG);
|
|
for (i = 0; i < fw->size;) {
|
|
if ( (fw->size - i) <fpgasize){
|
|
fpgasize=fw->size-i;
|
|
}
|
|
b = (u8 *) p + i;
|
|
if (opera1_xilinx_rw
|
|
(dev, OPERA_WRITE_FX2, 0x0, b , fpgasize,
|
|
OPERA_WRITE_MSG) != fpgasize
|
|
) {
|
|
err("error while transferring firmware");
|
|
ret = -EINVAL;
|
|
break;
|
|
}
|
|
i = i + fpgasize;
|
|
}
|
|
/* restart the CPU */
|
|
if (ret || opera1_xilinx_rw
|
|
(dev, 0xa0, 0xe600, &reset, 1,
|
|
OPERA_WRITE_MSG) != 1) {
|
|
err("could not restart the USB controller CPU.");
|
|
ret = -EINVAL;
|
|
}
|
|
}
|
|
}
|
|
kfree(p);
|
|
release_firmware(fw);
|
|
return ret;
|
|
}
|
|
|
|
static struct dvb_usb_device_properties opera1_properties = {
|
|
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
|
.usb_ctrl = CYPRESS_FX2,
|
|
.firmware = "dvb-usb-opera-01.fw",
|
|
.size_of_priv = sizeof(struct opera1_state),
|
|
|
|
.power_ctrl = opera1_power_ctrl,
|
|
.i2c_algo = &opera1_i2c_algo,
|
|
|
|
.rc.legacy = {
|
|
.rc_map_table = rc_map_opera1_table,
|
|
.rc_map_size = ARRAY_SIZE(rc_map_opera1_table),
|
|
.rc_interval = 200,
|
|
.rc_query = opera1_rc_query,
|
|
},
|
|
.read_mac_address = opera1_read_mac_address,
|
|
.generic_bulk_ctrl_endpoint = 0x00,
|
|
/* parameter for the MPEG2-data transfer */
|
|
.num_adapters = 1,
|
|
.adapter = {
|
|
{
|
|
.num_frontends = 1,
|
|
.fe = {{
|
|
.frontend_attach = opera1_frontend_attach,
|
|
.streaming_ctrl = opera1_streaming_ctrl,
|
|
.tuner_attach = opera1_tuner_attach,
|
|
.caps =
|
|
DVB_USB_ADAP_HAS_PID_FILTER |
|
|
DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
|
|
.pid_filter = opera1_pid_filter,
|
|
.pid_filter_ctrl = opera1_pid_filter_control,
|
|
.pid_filter_count = 252,
|
|
.stream = {
|
|
.type = USB_BULK,
|
|
.count = 10,
|
|
.endpoint = 0x82,
|
|
.u = {
|
|
.bulk = {
|
|
.buffersize = 4096,
|
|
}
|
|
}
|
|
},
|
|
}},
|
|
}
|
|
},
|
|
.num_device_descs = 1,
|
|
.devices = {
|
|
{"Opera1 DVB-S USB2.0",
|
|
{&opera1_table[0], NULL},
|
|
{&opera1_table[1], NULL},
|
|
},
|
|
}
|
|
};
|
|
|
|
static int opera1_probe(struct usb_interface *intf,
|
|
const struct usb_device_id *id)
|
|
{
|
|
struct usb_device *udev = interface_to_usbdev(intf);
|
|
|
|
if (le16_to_cpu(udev->descriptor.idProduct) == USB_PID_OPERA1_WARM &&
|
|
le16_to_cpu(udev->descriptor.idVendor) == USB_VID_OPERA1 &&
|
|
opera1_xilinx_load_firmware(udev, "dvb-usb-opera1-fpga-01.fw") != 0
|
|
) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (0 != dvb_usb_device_init(intf, &opera1_properties,
|
|
THIS_MODULE, NULL, adapter_nr))
|
|
return -EINVAL;
|
|
return 0;
|
|
}
|
|
|
|
static struct usb_driver opera1_driver = {
|
|
.name = "opera1",
|
|
.probe = opera1_probe,
|
|
.disconnect = dvb_usb_device_exit,
|
|
.id_table = opera1_table,
|
|
};
|
|
|
|
module_usb_driver(opera1_driver);
|
|
|
|
MODULE_AUTHOR("Mario Hlawitschka (c) dh1pa@amsat.org");
|
|
MODULE_AUTHOR("Marco Gittler (c) g.marco@freenet.de");
|
|
MODULE_DESCRIPTION("Driver for Opera1 DVB-S device");
|
|
MODULE_VERSION("0.1");
|
|
MODULE_LICENSE("GPL");
|