diff options
-rw-r--r-- | linux/drivers/media/dvb/vp7041/Kconfig | 18 | ||||
-rw-r--r-- | linux/drivers/media/dvb/vp7041/Makefile | 3 | ||||
-rw-r--r-- | linux/drivers/media/dvb/vp7041/vp7041.c | 1038 |
3 files changed, 0 insertions, 1059 deletions
diff --git a/linux/drivers/media/dvb/vp7041/Kconfig b/linux/drivers/media/dvb/vp7041/Kconfig deleted file mode 100644 index 757b3e434..000000000 --- a/linux/drivers/media/dvb/vp7041/Kconfig +++ /dev/null @@ -1,18 +0,0 @@ -config DVB_VP7041 - tristate "Twinhan Visionplus USB-Ter DVB-T/CTS Portable" - depends on DVB_CORE && USB - select FW_LOADER - help - Support for the external USB adapter made by Twinhan (and maybe others) - which is called "Twinhan Visionplus VisionDTV USB-Ter" and seems to - be identical to "CTS Portable" (Chinese Television System). - - These devices can be understood as budget ones, they only deliver - the MPEG data. - - This driver needs external firmware. Please use the command - "<kerneldir>/Documentation/dvb/get_dvb_firmware vp7041" to - download/extract it, and then copy it to /usr/lib/hotplug/firmware. - - Say Y if you own such a device and want to use it. You should build it as - a module. diff --git a/linux/drivers/media/dvb/vp7041/Makefile b/linux/drivers/media/dvb/vp7041/Makefile deleted file mode 100644 index 39c0dd9a4..000000000 --- a/linux/drivers/media/dvb/vp7041/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -obj-$(CONFIG_DVB_VP7041) += vp7041.o - -EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ diff --git a/linux/drivers/media/dvb/vp7041/vp7041.c b/linux/drivers/media/dvb/vp7041/vp7041.c deleted file mode 100644 index 9742d97d9..000000000 --- a/linux/drivers/media/dvb/vp7041/vp7041.c +++ /dev/null @@ -1,1038 +0,0 @@ -/* - * Driver for - * - * Twinhan VisionPlus VisionDTV USB-Ter DVB-T Device (VP7041) - * CTS Portable (Chinese Television System) - * - * http://www.twinhan.com/visiontv-2_4.htm - * http://www.2cts.tv/ctsportable/ - * - * This driver should also work with the CTS Portable since the - * windriver seems to be identical to the Twinhan one. - * - * vp7041.c - * - * Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.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. - * - * Acknowledgements - * Alex Woods for frequently answering question about usb and dvb - * stuff - * - * Some guys on the linux-dvb mailing list for encouraging me - * - * Peter Schildmann >peter.schildmann-nospam-at-web.de< for his - * user-level firmware loader, which saves a lot of time - * - * Ulf Hermenau for helping me out with traditional chinese. - * - * André Smoktun and Christian Frömmel - * - * Problem: - * - when tzap is running and you replug the device, a deadlock occures - * - disconnecting the device during mplayer is running brings a big oops - * somehow a clean usb exit has to be done - * - * TODO: - * - handling of USB disconnects (Oops when unplugged) - * - check init end deinit methods - * - different processor types (delays?) - * - big/litte endian ? - * - */ - -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/usb.h> -#include <linux/firmware.h> -#include <linux/pci.h> -#include <linux/version.h> -#include <linux/moduleparam.h> - -#include "dmxdev.h" -#include "dvb_demux.h" -#include "dvb_filter.h" -#include "dvb_frontend.h" -#include "dvb_net.h" - -static int debug; - -module_param(debug, int, 0x644); -MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); - -#define dprintk if (debug) printk - -/* Version information */ -#define DRIVER_VERSION "0.2" -#define DRIVER_DESC "Twinhan VisionPlus VisionDTV USB-Ter DVB-T / CTS Portable" -#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de" - -#define USB_TWINHAN_VENDOR_ID 0x1822 -// product ID befode loading the firmware -#define USB_VP7041_PRODUCT_PREFW_ID 0x3201 -// product ID afterwards -#define USB_VP7041_PRODUCT_ID 0x3202 - -/* USB Driver stuff */ - -/* table of devices that work with this driver */ -static struct usb_device_id vp7041_table [] = { - { USB_DEVICE(USB_TWINHAN_VENDOR_ID, USB_VP7041_PRODUCT_PREFW_ID) }, - { USB_DEVICE(USB_TWINHAN_VENDOR_ID, USB_VP7041_PRODUCT_ID) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE (usb, vp7041_table); - -static const char *firmware_filenames[] = { - "dvb-vp7041-2.42.fw", - "dvb-vp7041-2.422.fw" -}; - -#define COMMAND_PIPE 0x01 -#define RESULT_PIPE 0x81 -#define DATA_PIPE 0x82 - -#define VP7041_MAX_PIDS 16 - -struct vp7041_channel { - struct usb_vp7041 *vp; - - u8 id; - u16 pid; - u8 active; -}; - -/* data struct */ -struct usb_vp7041 { -/* usb */ - struct usb_device * udev; - - unsigned int command_pipe; - unsigned int result_pipe; - unsigned int data_pipe; - - struct urb *buf_urb; - u8 *buffer; - dma_addr_t dma_handle; - - struct vp7041_channel channel[VP7041_MAX_PIDS]; - - fe_status_t fe_status; - struct dvb_frontend_parameters fe_params; - int feed_count; - int streaming; - int disconnecting; - - struct semaphore usb_sem; - spinlock_t channel_lock; - -/* dvb */ - struct dvb_adapter *adapter; - struct dmxdev dmxdev; - struct dvb_demux demux; - struct dvb_net dvb_net; - struct dmx_frontend frontend; - -/* i2c */ - struct i2c_adapter *i2c; -}; - -static struct dvb_frontend_info vp7041_frontend_info = { - .name = "VisionPlus VisionDTV USB-Ter (VP7041) Frontend", - .type = FE_OFDM, - .frequency_min = 40000000, - .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 u8 vp7041_init_buf[] = { - 0x07, 0x00, 0x01, 0x33, 0x00, 0xc0, 0x80, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x86, 0xa0, 0xc2, 0x37, 0xf3, 0x24, 0xd2, 0x4e, 0x85, - 0x01, 0xa1, 0xcd, 0x7e, 0x50, 0xbb, 0x08, 0x01 -}; -/* 2004-07-12 - 0x07, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -*/ - - -static int vp7041_cmdmsg(struct usb_vp7041 *vp,u8 *buf, unsigned int buflen, - u8 *retbuf, unsigned int retbuflen, unsigned int *actbuflen) -{ - u8 *b; - int actual_size,ret = -ENOMEM; - - if (buf == NULL || buflen == 0) - return -EINVAL; - - if (vp->disconnecting) - return -EINVAL; - - if ((ret = down_interruptible(&vp->usb_sem))) { - err("Failed to down usb semaphore.\n"); - return ret; - } - - b = kmalloc(buflen,GFP_KERNEL); - if (b) { - memcpy(b,buf,buflen); - - if (debug) { - int i; - printk("%s: %d > ", __FUNCTION__,buflen); - for (i = 0; i < buflen; i++) - printk("%02x ", b[i]); - printk("\n"); - } - - ret = usb_bulk_msg(vp->udev,vp->command_pipe, - b,buflen,&actual_size,HZ); - - if (ret) - err("bulk message failed: %d (%d/%d)",ret,buflen,actual_size); - else - ret = actual_size != buflen ? -1 : 0; - - kfree(b); - } - - if (!ret && retbuf && retbuflen && actbuflen != NULL) { - ret = usb_bulk_msg(vp->udev,vp->result_pipe,retbuf, - retbuflen,actbuflen,HZ); - if (ret) - err("recv bulk message failed: %d",ret); - else if (debug) { - int i; - printk("%s: %d/%d > ", __FUNCTION__,*actbuflen,retbuflen); - for (i = 0; i < *actbuflen; i++) - printk("%02x ", retbuf[i]); - printk("\n"); - } - } - - up(&vp->usb_sem); - - return ret; -} - -static int vp7041_sndmsg(struct usb_vp7041 *vp,u8 *buf, unsigned int buflen) -{ - return vp7041_cmdmsg(vp,buf,buflen,NULL,0,NULL); -} - -static int vp7041_02_cmd(struct usb_vp7041 *vp, u8 a, u8 b, u8 c, u8 d, u8 e, u16 *val) -{ - u8 buf[64],bin[6] = { 0x02, a, b, c, d, e }; - int ret,len; - - *val = 0; - if ((ret = vp7041_cmdmsg(vp,bin,6,buf,64,&len))) - return ret; - - if (len != 2) { - err("unexpected return length: %d",len); - return -ENOSYS; - } - - *val = buf[0] << 8 | buf[1]; - dprintk("return stat: %d 0x%4x",*val,*val); - return 0; -} - -static int vp7041_03_cmd(struct usb_vp7041 *vp, u8 a, u8 b, u8 c, u8 d, u8 e) -{ - u8 buf[6] = { 0x03, a, b, c, d, e }; - return vp7041_sndmsg(vp,buf,6); -} - -static int vp7041_chk_tune (struct usb_vp7041 *vp,u8 stat, u16 *val) -{ - return vp7041_02_cmd(vp,0x11,0x81,stat,0x00,0x02,val); -} - -static int vp7041_tune(struct usb_vp7041 *vp, unsigned int freq, unsigned int bw) -{ - u8 bwbuf[] = { - 0x08,0x00, 0, 0x09, 0, 0, - 0x37,0x00,0x00, 0x38,0x00, 0, 0x39, 0, 0, 0x3a,0x00, 0, - 0x3b, 0, 0, 0x3c, 0, 0, 0x3d, 0, 0, 0x3e,0x00,0x00, - 0x3f,0x03,0xe8, 0x40,0x00,0x00, 0x41,0x03,0xf2, 0x42,0x00,0x01, - 0x43,0xb0,0xd0, - - 0x34,0x00,0x04, 0x01,0x00,0x01, 0x02,0x00,0x00, - 0x05,0x00,0x01, 0x36,0x00,0x0b, - 0x4f,0x00,0x01, - - 0x54,0x00,0x00, 0x79,0x00,0x05, - - 0xc3,0x00,0x01, 0x7e,0x00,0x00, 0x65,0x00,0x00, - - 0x2b,0x09,0x2d, 0x2c,0x00,0x05, 0x2d,0x09,0x2d, 0x2e,0x00,0x05, - 0x2f,0x0a,0x1a, 0x30,0x00,0x02, 0x31,0x0a,0x1a, 0x32,0x00,0x02, - 0x4f,0x00,0x00, - 0x00,0x00,0x0c, 0x00,0x00,0x00, - - 0x2b,0x08,0x28, 0x2c,0x00,0x0a, 0x2d,0x08,0x28, 0x2e,0x00,0x0a, - 0x2f,0x0d,0x78, 0x30,0x00,0x05, 0x31,0x0d,0x78, 0x32,0x00,0x05, - 0x4f,0x00,0x01, - - 0x00,0x00,0x02, 0x00,0x00,0x00 - }; - u8 prefeedbuf[] = { - 0x81,0x53, 0x81,0x54, 0x80,0x06, 0x80,0x07, 0x81,0x8e, 0x81,0x8f, - 0x81,0x90, 0x81,0x91, 0x81,0x92, 0x81,0x93, 0x81,0x94 - }; - u8 prefeedbuf2[] = { - 0x34,0x00,0x04, 0x01,0x00,0x01, 0x02,0x00,0x02, - 0x05,0x00,0x01, 0x36,0x00,0x00, 0x4f,0x00,0x00, - 0x54,0x00,0x00, 0x79,0x00,0x05, - - 0x03,0x00,0x01, - 0x04,0x00,0x01, 0x82,0x00,0x01, 0x81,0x00,0x02, - - 0xc3,0x00,0x01, 0x7e,0x00,0x00, 0x65,0x00,0x00, - 0x00,0x00,0x04, 0x00,0x00,0x00 - }; - u16 vpfreq; - u8 vu, p2, p1, p0; - int i,ret; - u16 tunestat; - - vp->fe_status = 0; - -// from at76c651.c it is a TUA6010XS - vpfreq = (freq + 36125000) / 62500; - - dprintk("tuning to freq: %u (%2x,%2x), bw: %u, bufsize: %d", - freq,(vpfreq >> 8) & 0xff, vpfreq & 0xff,bw,sizeof(bwbuf)); - - if (freq > 400000000) - vu = 1, p2 = 1, p1 = 0, p0 = 1; - else if (freq > 140000000) - vu = 0, p2 = 1, p1 = 1, p0 = 0; - else - vu = 0, p2 = 0, p1 = 1, p0 = 1; - - if ((ret = vp7041_03_cmd(vp,0x10,0x04,0x41,0x61,0x00)) || - (ret = vp7041_03_cmd(vp,0xc2, - (vpfreq >> 8) & 0x7f, - vpfreq & 0xff, - 0x8e, - (vu << 7) | (p2 << 2) | (p1 << 1) | p0 )) || - (ret = vp7041_03_cmd(vp,0x10,0x04,0x41,0x61,0x80)) ) - return ret; - - switch (bw) { - case BANDWIDTH_6_MHZ: - bwbuf[2] = 0x7e; bwbuf[4] = 0xbe; bwbuf[5] = 0xe9; - bwbuf[11] = 0x21; bwbuf[13] = 0xd0; bwbuf[14] = 0x40; - bwbuf[17] = 0x70; bwbuf[19] = 0xb6; bwbuf[20] = 0x2b; - bwbuf[22] = 0x02; bwbuf[23] = 0x33; bwbuf[25] = 0x8e; - bwbuf[26] = 0xd5; - break; - case BANDWIDTH_7_MHZ: - bwbuf[2] = 0x93; bwbuf[4] = 0xde; bwbuf[5] = 0xbb; - bwbuf[11] = 0x1c; bwbuf[13] = 0xfb; bwbuf[14] = 0xa5; - bwbuf[17] = 0x60; bwbuf[19] = 0x9c; bwbuf[20] = 0x25; - bwbuf[22] = 0x01; bwbuf[23] = 0xe3; bwbuf[25] = 0x0c; - bwbuf[26] = 0xb7; - break; - case BANDWIDTH_8_MHZ: - bwbuf[2] = 0xa8; bwbuf[4] = 0xfe; bwbuf[5] = 0x8c; - bwbuf[11] = 0x19; bwbuf[13] = 0x5c; bwbuf[14] = 0x30; - bwbuf[17] = 0x54; bwbuf[19] = 0x88; bwbuf[20] = 0xa0; - bwbuf[22] = 0x01; bwbuf[23] = 0xa6; bwbuf[25] = 0xab; - bwbuf[26] = 0x20; - break; - default: - err("bandwidth: %d not supported",bw); - return -ENOSYS; - } - - - for (i=0; i < sizeof(bwbuf); i+=3) - if ((ret = vp7041_03_cmd(vp,0x10,0x00,bwbuf[i],bwbuf[i+1],bwbuf[i+2]))) - return ret; - - do { - ret = vp7041_chk_tune (vp, 0xb2, &tunestat); - } while (ret == 0 && !(tunestat & 0x01) && !(tunestat & 0x02)); - - if ((ret = vp7041_chk_tune (vp, 0xab, &tunestat))) - return ret; - - switch (tunestat) { - case 0x01: - for (i=0; i < sizeof(prefeedbuf); i += 2) { - if ((ret = vp7041_02_cmd(vp,0x11,prefeedbuf[i],prefeedbuf[i+1], - 0x00,0x02,&tunestat))) - return ret; - } - vp->fe_status = FE_HAS_SIGNAL | FE_HAS_VITERBI | FE_HAS_SYNC | - FE_HAS_CARRIER; - break; - case 0x00: // Tuning failed - return 0; - break; - default: - dprintk("Unknown tunestat (0x%x).\n",tunestat); - break; - } - - for (i=0; i < sizeof(prefeedbuf2); i+=3) - if ((ret = vp7041_03_cmd(vp,0x10,0x00,prefeedbuf2[i],prefeedbuf2[i+1], - prefeedbuf2[i+2]))) - return ret; - vp->fe_status |= FE_HAS_LOCK; - return ret; -} - -#if 0 -/* - * check the signal strength and quality - * (TODO reverse engineer the result) - */ -static int vp7041_signal_strength(struct usb_vp7041 *vp) -{ - u8 b_out[] = { - 0x48, 0xa7, 0xa8, 0x9e, 0x9f, 0xa4, 0x7c, 0x74, 0x75, 0x45 - }; - u16 vals[sizeof(b_out)]; - int i, ret; - - for (i=0; i < sizeof(b_out); i++) - if ((ret = vp7041_chk_tune(vp,b_out[i],&vals[i]))) - return ret; - - return 0; -} - -/* remote control (0x04) */ -/* - * TODO: a tasklet should run with a delay of (1/10 second) - * fill an appropriate event device ? - */ -static int vp7041_rc_status(struct usb_vp7041 *vp) -{ - u8 b_out[1] = { 0x04 },b_in[5]; - unsigned int actlen; - int ret = 0; - - ret = vp7041_cmdmsg(vp,b_out,1,b_in,5,&actlen); - if (!ret) { - dprintk("remote control result: %x %x %x %x %x", - b_in[0],b_in[1],b_in[2],b_in[3],b_in[4]); - } else - err("remote control cmd failed: %d",ret); - return ret; -} -#endif -static struct vp7041_channel *vp7041_channel_allocate(struct usb_vp7041 *vp) -{ - int i; - unsigned long flags; - struct vp7041_channel *ch = NULL; - - spin_lock_irqsave(&vp->channel_lock,flags); - for (i = 0; i < VP7041_MAX_PIDS; i++) - if (!vp->channel[i].active) { - ch = vp->channel + i; - ch->active = 1; - break; - } - spin_unlock_irqrestore(&vp->channel_lock,flags); - - return ch; -} - -static int vp7041_set_channel(struct vp7041_channel *channel) -{ - dprintk("set channel: feed_count: %d\n",channel->vp->feed_count); - return vp7041_03_cmd(channel->vp,0x10, 0x00, channel->id, - 0x20 + (channel->pid >> 8), channel->pid & 0xff); -} - -static int vp7041_del_channel(struct vp7041_channel *channel) -{ - // I think, spinlock at this point is not necessary, but maybe I'm wrong - int ret; - dprintk("del_channel: vp = %p, id = %x, active=%d, streamcount=%d pid=%x\n", - channel->vp,channel->id,channel->active,channel->vp->feed_count,channel->pid); - ret = vp7041_03_cmd(channel->vp,0x10, 0x00, channel->id, 0, 0); - channel->active = 0; - return ret; -} - -static void vp7041_urb_complete(struct urb *urb, struct pt_regs *ptregs) -{ - struct usb_vp7041 *vp = urb->context; - - if (!vp->streaming) - return; - - if (urb->status == 0) { - if (urb->actual_length % 188) - dprintk("TS Packets: %d, %d\n", urb->actual_length/188, - urb->actual_length % 188); - dvb_dmx_swfilter_packets(&vp->demux, (u8*) urb->transfer_buffer, - urb->actual_length/188); - } - - if (vp->streaming) - usb_submit_urb(urb,GFP_KERNEL); -} - -static void vp7041_stop_xfer(struct usb_vp7041 *vp) -{ - vp->streaming = 0; - usb_unlink_urb(vp->buf_urb); - if(!vp->disconnecting) { - int i; - for (i = 0; i < VP7041_MAX_PIDS; i++) - vp7041_del_channel(&vp->channel[i]); - vp->feed_count = 0; - - vp7041_03_cmd(vp,0x10, 0x00, 0x91, 0x00, 0x01); - } -} - - -static int vp7041_start_xfer(struct usb_vp7041 *vp) -{ - int ret; - - if (vp->streaming || vp->disconnecting) - return 0; - - usb_fill_bulk_urb( vp->buf_urb, vp->udev, vp->data_pipe, - vp->buffer, 8192, vp7041_urb_complete, vp); - vp->buf_urb->transfer_flags = 0; - vp->buf_urb->timeout = 0; - - // starting transfer in device - if ((ret = vp7041_03_cmd(vp,0x10, 0x00, 0x91, 0x00, 0x00))) - return ret; - - if ((ret = usb_submit_urb(vp->buf_urb,GFP_KERNEL))) { - vp7041_stop_xfer(vp); - err("could not submit buffer urb."); - return ret; - } - - vp->streaming = 1; - - return 0; -} - -static int vp7041_start_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - struct usb_vp7041 *vp = dvbdmxfeed->demux->priv; - struct vp7041_channel *channel; - - dprintk("pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid, - dvbdmxfeed->type); - - if (!dvbdmx->dmx.frontend) - return -EINVAL; - - if ((channel = vp7041_channel_allocate(vp)) == NULL) - return -EBUSY; - - dvbdmxfeed->priv = channel; - channel->pid = dvbdmxfeed->pid; - - vp7041_set_channel(channel); - - if (0 == vp->feed_count++) - return vp7041_start_xfer(vp); - - return 0; -} - -static int vp7041_stop_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct usb_vp7041 *vp = dvbdmxfeed->demux->priv; - struct vp7041_channel *channel = (struct vp7041_channel *) - dvbdmxfeed->priv; - - dprintk("stopfeed pid: 0x%04x, feedtype: %d",dvbdmxfeed->pid, - dvbdmxfeed->type); - - if (channel == NULL) - err("channel in dmxfeed->priv was NULL"); - else - vp7041_del_channel(channel); - - if (--vp->feed_count == 0) - vp7041_stop_xfer(vp); - - return 0; -} - -static int vp7041_device_init (struct usb_vp7041 *vp) -{ - int i,ret; - u16 stat; - u8 initbuf[] = { - 0x03,0x00,0x03, 0x04,0x00,0x07, - - 0x06,0x00,0xb2, 0x07,0x23,0x1e, 0x08,0x00,0xa8, 0x09,0xfe,0x8c, - 0x0a,0x00,0x00, 0x0b,0x00,0x02, 0x0c,0x00,0x0a, 0x0f,0x01,0xff, - - 0x24,0x03,0x99, - - 0x13,0x00,0x01, 0x14,0xcc,0xcd, 0x15,0x02,0x6f, 0x16,0x00,0x80, - 0x17,0x00,0xa6, 0x18,0x00,0xc3, 0x19,0x00,0x3d, 0x1a,0x00,0x01, - 0x1b,0xd2,0x06, 0x1c,0x94,0x7b, 0x1d,0x00,0x00, 0x1e,0x00,0x5a, - 0x1f,0x00,0x21, 0x20,0x00,0x17, - - 0x57,0x00,0x00, - - 0x21,0x00,0x02, 0x22,0x02,0x20, 0x23,0x00,0x00, 0x25,0x00,0x05, - 0x26,0x00,0x04, 0x27,0x00,0x87, 0x28,0x00,0x87, - - 0x2b,0x08,0x28, 0x2c,0x00,0x0a, 0x2d,0x08,0x28, 0x2e,0x00,0x0a, - 0x2f,0x0d,0x78, 0x30,0x00,0x05, 0x31,0x0d,0x78, 0x32,0x00,0x05, - 0x33,0x00,0x04, 0x34,0x00,0x04, 0x35,0x00,0x80, 0x36,0x00,0x0b, - 0x37,0x00,0x00, 0x38,0x00,0x19, 0x39,0x5c,0x30, 0x3a,0x00,0x54, - 0x3b,0x88,0xa0, 0x3c,0x01,0xa6, 0x3d,0xab,0x20, 0x3e,0x00,0x00, - 0x3f,0x03,0xe8, 0x40,0x00,0x00, 0x41,0x03,0xf2, 0x42,0x00,0x01, - 0x43,0xb0,0xd0, 0x44,0x00,0x00, 0x45,0x00,0x00, 0x47,0x00,0x00, - 0x4d,0x00,0x06, 0x4e,0x00,0x80, 0x4f,0x00,0x01, - - 0x5c,0x00,0x80, - - 0x60,0x00,0x10, 0x61,0x00,0x09, 0x6a,0x00,0x80, 0x6b,0x00,0x80, - 0x6c,0x00,0x80, - - 0x7a,0x0b,0x33, 0x7e,0x00,0x00, - - 0x81,0x00,0x00, 0x82,0x00,0x01, - - 0x87,0x00,0x01, 0x8f,0x00,0x00, - - 0xab,0x00,0xe2, 0xac,0x00,0xa0, 0xad,0x00,0x1d, 0xae,0x03,0xd3, - 0xaf,0x03,0xe6, 0xb0,0x00,0x13, 0xb1,0x00,0x16, 0xb2,0x03,0xfb, - 0xb3,0x03,0xee, 0xb4,0x03,0xfe, 0xb5,0x00,0x0c, 0xb6,0x00,0x06, - 0xb7,0x03,0xf9, 0xb8,0x03,0xf9, 0xb9,0x00,0x03, 0xba,0x00,0x06, - 0xbc,0x03,0xfb, 0xbd,0x03,0xfd, 0xbe,0x00,0x02, 0xbf,0x00,0x03, - 0xc0,0x00,0x01, - - 0xc2,0x00,0x00, 0xc3,0x00,0x01, - - 0xce,0x7f,0xff, 0xcf,0x0f,0xff, - - 0xa9,0x00,0x06, - - 0x8e,0x00,0x00, 0x8f,0x00,0x01, 0x90,0x00,0x01, 0x91,0x00,0x01, - 0x92,0x00,0x03, 0x93,0x01,0x00, - - 0x99,0x00,0x00, 0x99,0x00,0x00, 0x99,0x00,0x00, 0x99,0x00,0x00, - 0x99,0x00,0x00, 0x99,0x00,0x00, 0x99,0x00,0x00, 0x99,0x00,0x00, - 0x99,0x00,0x00, 0x99,0x00,0x00, 0x99,0x00,0x00, 0x99,0x00,0x00, - 0x99,0x00,0x00, 0x99,0x00,0x00, 0x99,0x00,0x00, 0x99,0x00,0x00, - - 0x7f,0x00,0x00 - }; - if ((ret = vp7041_sndmsg(vp,vp7041_init_buf,sizeof(vp7041_init_buf)))) - return ret; - - if ((ret = vp7041_03_cmd(vp,0x10,0x04,0x04,0x00,0x00))) return ret; - if ((ret = vp7041_02_cmd(vp,0x11,0x84,0x01,0x00,0x02,&stat))) return ret; - if (stat != 0x01b3) { - dprintk("unexpected known value returned during initialization (%.4x)",stat); - return -ENOSYS; - } - if ((ret = vp7041_03_cmd(vp,0x10,0x00,0x00,0x00,0x04))) return ret; - if ((ret = vp7041_03_cmd(vp,0x10,0x04,0x00,0x81,0x2c))) return ret; - if ((ret = vp7041_03_cmd(vp,0x10,0x04,0x00,0x00,0x04))) return ret; - if ((ret = vp7041_03_cmd(vp,0x10,0x04,0x03,0x90,0x00))) return ret; - if ((ret = vp7041_03_cmd(vp,0x10,0x04,0x05,0x00,0x01))) return ret; - - for (i = 0; i < sizeof(initbuf); i+=3) - if ((ret = vp7041_03_cmd(vp,0x10,0x00,initbuf[i], - initbuf[i+1],initbuf[i+2]))) - return ret; - - return 0; -} - -static int vp7041_dvb_init(struct usb_vp7041 *vp) -{ - int ret; - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,4) - if ((ret = dvb_register_adapter(&vp->adapter, DRIVER_DESC)) < 0) { -#else - if ((ret = dvb_register_adapter(&vp->adapter, DRIVER_DESC , - THIS_MODULE)) < 0) { -#endif - dprintk("dvb_register_adapter failed: error %d", ret); - goto err; - } - vp->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; - - vp->demux.priv = (void *)vp; - vp->demux.filternum = 15; - vp->demux.feednum = 15; - vp->demux.start_feed = vp7041_start_feed; - vp->demux.stop_feed = vp7041_stop_feed; - vp->demux.write_to_decoder = NULL; - if ((ret = dvb_dmx_init(&vp->demux)) < 0) { - err("dvb_dmx_init failed: error %d",ret); - goto err_dmx; - } - - vp->dmxdev.filternum = vp->demux.filternum; - vp->dmxdev.demux = &vp->demux.dmx; - vp->dmxdev.capabilities = 0; - if ((ret = dvb_dmxdev_init(&vp->dmxdev, vp->adapter)) < 0) { - err("dvb_dmxdev_init failed: error %d",ret); - goto err_dmx_dev; - } - - vp->frontend.source = DMX_FRONTEND_0; - if ((ret = vp->demux.dmx.add_frontend(&vp->demux.dmx, - &vp->frontend)) < 0) { - err("dmx_add_frontend failed: error %d", ret); - goto err_add_fe; - } - - if ((ret = vp->demux.dmx.connect_frontend(&vp->demux.dmx, - &vp->frontend)) < 0) { - err("dmx_connect_frontend failed: error %d\n",ret); - goto err_conn_fe; - } - - vp->fe_status = 0; - - dvb_net_init(vp->adapter, &vp->dvb_net, &vp->demux.dmx); - - goto success; -err_conn_fe: - vp->demux.dmx.remove_frontend(&vp->demux.dmx, &vp->frontend); -err_add_fe: - dvb_dmxdev_release(&vp->dmxdev); -err_dmx_dev: - dvb_dmx_release(&vp->demux); -err_dmx: - dvb_unregister_adapter(vp->adapter); -err: - return ret; -success: - return 0; -} - -static int vp7041_dvb_exit(struct usb_vp7041 *vp) -{ - info("unregistering DVB part"); - dvb_net_release(&vp->dvb_net); - vp->demux.dmx.close(&vp->demux.dmx); - vp->demux.dmx.remove_frontend(&vp->demux.dmx, &vp->frontend); - dvb_dmxdev_release(&vp->dmxdev); - dvb_dmx_release(&vp->demux); - dvb_unregister_adapter(vp->adapter); - - return 0; -} - -static int vp7041_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg) -{ - struct usb_vp7041 *vp = fe->data; - - switch (cmd) { - case FE_GET_INFO: - dprintk("FE_GET_INFO\n"); - memcpy(arg, &vp7041_frontend_info, - sizeof (struct dvb_frontend_info)); - break; - case FE_READ_STATUS: { - fe_status_t *status = (fe_status_t *)arg; - dprintk("FE_READ_STATUS\n"); - *status = vp->fe_status; - } - break; - case FE_READ_BER: - dprintk("FE_READ_BER\n"); - return -EINVAL; - break; - case FE_READ_SIGNAL_STRENGTH: { -// TODO vp7041_signal_strength(vp); - u16 *val = (u16*) arg; - *val = 0xFFFF; - break; - } - case FE_READ_SNR: { - u16 *val = (u16*) arg; - *val = 0xFFFF; -// TODO vp7041_signal_strength - dprintk("FE_READ_SNR\n"); - break; - } - case FE_READ_UNCORRECTED_BLOCKS: - dprintk("FE_READ_UNCORRECTED_BLOCKS\n"); - return -EINVAL; - break; - case FE_SET_FRONTEND: { - struct dvb_frontend_parameters *p = - (struct dvb_frontend_parameters *) arg; - vp->fe_params = *p; - dprintk("FE_SET_FRONTEND, freq: %d rate: %d bw:%d inv: %d\n", - p->frequency,p->u.qam.symbol_rate,p->u.ofdm.bandwidth,p->inversion); - return vp7041_tune(vp,p->frequency,p->u.ofdm.bandwidth); - break; - } - case FE_GET_FRONTEND: { - struct dvb_frontend_parameters *p = - (struct dvb_frontend_parameters *) arg; - dprintk("FE_GET_FRONTEND\n"); - *p = vp->fe_params; - } - break; - case FE_SLEEP: - dprintk("FE_SLEEP\n"); - return -ENOSYS; - break; - case FE_INIT: - dprintk("FE_INIT\n"); - return -EINVAL; - break; - default: - return -EINVAL; - } - return 0; -} - -static int vp7041_frontend_init(struct usb_vp7041 *vp) -{ - int ret; - - ret = dvb_register_frontend(vp7041_ioctl, vp->adapter, vp, &vp7041_frontend_info, THIS_MODULE); - if (ret) - return ret; - return 0; -} - -static void vp7041_frontend_exit(struct usb_vp7041 *vp) -{ - dvb_unregister_frontend(vp7041_ioctl, vp->adapter); -} - -static int vp7041_exit (struct usb_vp7041 *vp) -{ - usb_free_urb(vp->buf_urb); - pci_free_consistent(NULL,8192,vp->buffer,vp->dma_handle); - return 0; -} - -static int vp7041_init(struct usb_vp7041 *vp) -{ - int ret,i; - unsigned long flags; - - sema_init(&vp->usb_sem, 1); - spin_lock_init(&vp->channel_lock); - - vp->command_pipe = usb_sndbulkpipe(vp->udev, COMMAND_PIPE); - vp->result_pipe = usb_rcvbulkpipe(vp->udev, RESULT_PIPE); - vp->data_pipe = usb_rcvbulkpipe(vp->udev, DATA_PIPE); - - // when reloading the driver w/o replugging the device - // a timeout occures, this should help - usb_clear_halt(vp->udev,vp->command_pipe); - usb_clear_halt(vp->udev,vp->result_pipe); - usb_clear_halt(vp->udev,vp->data_pipe); - - vp->buffer = pci_alloc_consistent(NULL,8192, &vp->dma_handle); - memset(vp->buffer,0,8192); - if (!(vp->buf_urb = usb_alloc_urb(0,GFP_KERNEL))) { - pci_free_consistent(NULL,8192,vp->buffer,vp->dma_handle); - return -ENOMEM; - } - spin_lock_irqsave(&vp->channel_lock,flags); - for (i=0; i < VP7041_MAX_PIDS; i++) { - vp->channel[i].vp = vp; - vp->channel[i].id = 0x99+i; - vp->channel[i].active = 0; - } - spin_unlock_irqrestore(&vp->channel_lock,flags); - - ret = vp7041_device_init(vp); - if (ret) { - vp7041_exit(vp); - return ret; - } - - ret = vp7041_dvb_init(vp); - if (ret) { - vp7041_exit(vp); - return ret; - } - - ret = vp7041_frontend_init(vp); - if (ret) { - vp7041_dvb_exit(vp); - vp7041_exit(vp); - return ret; - } - - return 0; -} - -static int vp7041_loadfirmware(struct usb_device *udev) -{ - const struct firmware *fw = NULL; - int ret = 0, i; - for (i = 0; i < sizeof(firmware_filenames)/sizeof(char*); i++) { - if ((ret = request_firmware(&fw, firmware_filenames[i], &udev->dev)) == 0) { - info("found firmware file (%s).",firmware_filenames[i]); - break; - } - dprintk("Firmware '%s' not found. (%d)\n",firmware_filenames[i],ret); - } - - - if (fw == NULL) { - err("Did not find a valid firmware."); - return -EINVAL; - } - - if (!(fw->size % 22)) { - int i; - u16 addr; - u8 *b,*p = kmalloc(fw->size,GFP_KERNEL); - if (p != NULL) { - /* - * you cannot use the fw->data as buffer for - * usb_control_msg, a new buffer has to be - * created - */ - memcpy(p,fw->data,fw->size); - for(i = 0; i < fw->size; i += 22) { - b = (u8 *) &p[i]; - addr = *((u16 *) &b[3]); - - ret = usb_control_msg(udev, usb_sndctrlpipe(udev,0), - 0xa0, USB_TYPE_VENDOR, addr, 0x00, &b[6], - (u16) b[1], 5*HZ); - - if (ret != b[1]) { - err("error while transferring firmware " - "(transferred size: %d, block size: %d)", - ret,b[1]); - ret = -EINVAL; - break; - } - } - kfree(p); - ret = 0; - } else - ret = -ENOMEM; - } else { - err("invalid firmware filesize."); - ret = -ENODEV; - } - release_firmware(fw); - - return ret; -} - - -static int vp7041_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct usb_vp7041 *vp = NULL; - - int retval = -ENOMEM; - - switch (udev->descriptor.idProduct) { - case USB_VP7041_PRODUCT_PREFW_ID: - retval = vp7041_loadfirmware(udev); - break; - case USB_VP7041_PRODUCT_ID: - vp = kmalloc(sizeof(struct usb_vp7041),GFP_KERNEL); - if (vp == NULL) { - err("no memory"); - return retval; - } - memset(vp,0,sizeof(struct usb_vp7041)); - vp->udev = udev; - usb_set_intfdata(intf, vp); - - retval = vp7041_init(vp); - - break; - default: - err("something went very wrong, " - "unknown product ID: %.4x",udev->descriptor.idProduct); - retval = -ENODEV; - break; - } - if (retval == 0) - info( DRIVER_DESC " successfully initialized and connected."); - else - info( DRIVER_DESC " error while loading driver (%d)",retval); - return retval; -} - -static void vp7041_disconnect(struct usb_interface *intf) -{ - struct usb_vp7041 *vp = usb_get_intfdata(intf); - usb_set_intfdata(intf,NULL); - - if (vp != NULL) { - vp->disconnecting = 1; - vp7041_stop_xfer(vp); - vp7041_frontend_exit(vp); - vp7041_dvb_exit(vp); - vp7041_exit(vp); - kfree(vp); - } - - info( DRIVER_DESC " successfully deinitialized and disconnected."); -} - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver vp7041_driver = { - .owner = THIS_MODULE, - .name = "vp7041", - .probe = vp7041_probe, - .disconnect = vp7041_disconnect, - .id_table = vp7041_table, -}; - -/* module stuff */ -static int __init usb_vp7041_init(void) -{ - int result; - - if ((result = usb_register(&vp7041_driver))) { - err("usb_register failed. Error number %d",result); - return result; - } - - return 0; -} - -static void __exit usb_vp7041_exit(void) -{ - /* deregister this driver from the USB subsystem */ - usb_deregister(&vp7041_driver); -} - -module_init (usb_vp7041_init); -module_exit (usb_vp7041_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); |