From: Michael Hunold - B2C2: move generic b2c2 code a separate module, added basic b2c2-usb support - [DVB] Skystar2: add mt312/vp310 support Signed-off-by: Michael Hunold Signed-off-by: Andrew Morton --- 25-akpm/drivers/media/dvb/b2c2/Kconfig | 16 25-akpm/drivers/media/dvb/b2c2/Makefile | 3 25-akpm/drivers/media/dvb/b2c2/b2c2-common.c | 214 +++++++++ 25-akpm/drivers/media/dvb/b2c2/b2c2-usb-core.c | 538 +++++++++++++++++++++++++ 25-akpm/drivers/media/dvb/b2c2/skystar2.c | 83 ++- 5 files changed, 829 insertions(+), 25 deletions(-) diff -puN /dev/null drivers/media/dvb/b2c2/b2c2-common.c --- /dev/null Thu Apr 11 07:25:15 2002 +++ 25-akpm/drivers/media/dvb/b2c2/b2c2-common.c Fri Dec 10 15:14:12 2004 @@ -0,0 +1,214 @@ +/* + * b2c2-common.c - common methods for the B2C2/Technisat SkyStar2 PCI DVB card and + * for the B2C2/Technisat Sky/Cable/AirStar USB devices + * based on the FlexCopII/FlexCopIII by B2C2, Inc. + * + * Copyright (C) 2003 Vadim Catana, skystar@moldova.cc + * + * FIX: DISEQC Tone Burst in flexcop_diseqc_ioctl() + * FIX: FULL soft DiSEqC for skystar2 (FlexCopII rev 130) VP310 equipped + * Vincenzo Di Massa, hawk.it at tiscalinet.it + * + * Converted to Linux coding style + * Misc reorganization, polishing, restyling + * Roberto Ragusa, r.ragusa at libero.it + * + * Added hardware filtering support, + * Niklas Peinecke, peinecke at gdv.uni-hannover.de + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * 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 Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ +#include "stv0299.h" +#include "mt352.h" +#include "mt312.h" + +static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio) +{ + u8 aclk = 0; + u8 bclk = 0; + + if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; } + else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; } + else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; } + else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; } + else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; } + else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; } + + stv0299_writereg (fe, 0x13, aclk); + stv0299_writereg (fe, 0x14, bclk); + stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff); + stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff); + stv0299_writereg (fe, 0x21, (ratio ) & 0xf0); + + return 0; +} + +static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + u8 buf[4]; + u32 div; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; +// struct adapter* adapter = (struct adapter*) fe->dvb->priv; + + div = params->frequency / 125; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0x84; // 0xC4 + buf[3] = 0x08; + + if (params->frequency < 1500000) buf[3] |= 0x10; + +// if (i2c_transfer (&adapter->i2c_adap, &msg, 1) != 1) return -EIO; + return 0; +} + +static u8 samsung_tbmu24112_inittab[] = { + 0x01, 0x15, + 0x02, 0x30, + 0x03, 0x00, + 0x04, 0x7D, + 0x05, 0x35, + 0x06, 0x02, + 0x07, 0x00, + 0x08, 0xC3, + 0x0C, 0x00, + 0x0D, 0x81, + 0x0E, 0x23, + 0x0F, 0x12, + 0x10, 0x7E, + 0x11, 0x84, + 0x12, 0xB9, + 0x13, 0x88, + 0x14, 0x89, + 0x15, 0xC9, + 0x16, 0x00, + 0x17, 0x5C, + 0x18, 0x00, + 0x19, 0x00, + 0x1A, 0x00, + 0x1C, 0x00, + 0x1D, 0x00, + 0x1E, 0x00, + 0x1F, 0x3A, + 0x20, 0x2E, + 0x21, 0x80, + 0x22, 0xFF, + 0x23, 0xC1, + 0x28, 0x00, + 0x29, 0x1E, + 0x2A, 0x14, + 0x2B, 0x0F, + 0x2C, 0x09, + 0x2D, 0x05, + 0x31, 0x1F, + 0x32, 0x19, + 0x33, 0xFE, + 0x34, 0x93, + 0xff, 0xff, +}; + +static struct stv0299_config samsung_tbmu24112_config = { + .demod_address = 0x68, + .inittab = samsung_tbmu24112_inittab, + .mclk = 88000000UL, + .invert = 0, + .enhanced_tuning = 0, + .skip_reinit = 0, + .lock_output = STV0229_LOCKOUTPUT_LK, + .volt13_op0_op1 = STV0299_VOLT13_OP1, + .min_delay_ms = 100, + .set_symbol_rate = samsung_tbmu24112_set_symbol_rate, + .pll_set = samsung_tbmu24112_pll_set, +}; + + + + + +static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe) +{ + static u8 mt352_clock_config [] = { 0x89, 0x10, 0x2d }; + static u8 mt352_reset [] = { 0x50, 0x80 }; + static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; + static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0xa1 }; + static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; + + mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); + udelay(2000); + mt352_write(fe, mt352_reset, sizeof(mt352_reset)); + mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); + + mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); + mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); + + return 0; +} + +int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf) +{ + u32 div; + unsigned char bs = 0; + + #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ + div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; + + if (params->frequency >= 48000000 && params->frequency <= 154000000) bs = 0x09; + if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a; + if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08; + + pllbuf[0] = 0xc2; // Note: non-linux standard PLL i2c address + pllbuf[1] = div >> 8; + pllbuf[2] = div & 0xff; + pllbuf[3] = 0xcc; + pllbuf[4] = bs; + + return 0; +} + +static struct mt352_config samsung_tdtc9251dh0_config = { + + .demod_address = 0x0f, + .demod_init = samsung_tdtc9251dh0_demod_init, + .pll_set = samsung_tdtc9251dh0_pll_set, +}; + +static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + u8 buf[4]; + u32 div; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; +// struct adapter* adapter = (struct adapter*) fe->dvb->priv; + + div = (params->frequency + (125/2)) / 125; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = (div >> 0) & 0xff; + buf[2] = 0x84 | ((div >> 10) & 0x60); + buf[3] = 0x80; + + if (params->frequency < 1550000) + buf[3] |= 0x02; + + //if (i2c_transfer (&adapter->i2c_adap, &msg, 1) != 1) return -EIO; + return 0; +} + +static struct mt312_config skystar23_samsung_tbdu18132_config = { + + .demod_address = 0x0e, + .pll_set = skystar23_samsung_tbdu18132_pll_set, +}; diff -puN /dev/null drivers/media/dvb/b2c2/b2c2-usb-core.c --- /dev/null Thu Apr 11 07:25:15 2002 +++ 25-akpm/drivers/media/dvb/b2c2/b2c2-usb-core.c Fri Dec 10 15:14:12 2004 @@ -0,0 +1,538 @@ +/* + * Copyright (C) 2004 Patrick Boettcher , + * Luca Bertagnolio <>, + * + * based on information provided by John Jurrius from BBTI, Inc. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "dmxdev.h" +#include "dvb_demux.h" +#include "dvb_filter.h" +#include "dvb_net.h" +#include "dvb_frontend.h" + +/* debug */ +#define dprintk(level,args...) \ + do { if ((debug & level)) { printk(args); } } while (0) +#define debug_dump(b,l) if (debug) {\ + int i; deb_xfer("%s: %d > ",__FUNCTION__,l); \ + for (i = 0; i < l; i++) deb_xfer("%02x ", b[i]); \ + deb_xfer("\n");\ +} + +static int debug; +module_param(debug, int, 0x644); +MODULE_PARM_DESC(debug, "set debugging level (1=info,ts=2,ctrl=4 (or-able))."); + +#define deb_info(args...) dprintk(0x01,args) +#define deb_ts(args...) dprintk(0x02,args) +#define deb_ctrl(args...) dprintk(0x04,args) + +/* Version information */ +#define DRIVER_VERSION "0.0" +#define DRIVER_DESC "Driver for B2C2/Technisat Air/Cable/Sky-2-PC USB devices" +#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de" + +/* transfer parameters */ +#define B2C2_USB_FRAMES_PER_ISO 4 +#define B2C2_USB_NUM_ISO_URB 4 /* TODO check out a good value */ + +#define B2C2_USB_CTRL_PIPE_IN usb_rcvctrlpipe(b2c2->udev,0) +#define B2C2_USB_CTRL_PIPE_OUT usb_sndctrlpipe(b2c2->udev,0) +#define B2C2_USB_DATA_PIPE usb_rcvisocpipe(b2c2->udev,0x81) + +struct usb_b2c2_usb { + struct usb_device *udev; + struct usb_interface *uintf; + + u8 *iso_buffer; + int buffer_size; + dma_addr_t iso_dma_handle; + struct urb *iso_urb[B2C2_USB_NUM_ISO_URB]; +}; + + +/* + * USB + * 10 90 34 12 78 56 04 00 + * usb_control_msg(udev, usb_sndctrlpipe(udev,0), + * 0x90, + * 0x10, + * 0x1234, + * 0x5678, + * buf, + * 4, + * 5*HZ); + * + * extern int usb_control_msg(struct usb_device *dev, unsigned int pipe, + * __u8 request, + * __u8 requesttype, + * __u16 value, + * __u16 index, + * void *data, + * __u16 size, + * int timeout); + * + */ + +/* request types */ +typedef enum { + RTYPE_READ_DW = (1 << 6), + RTYPE_WRITE_DW_1 = (3 << 6), + RTYPE_READ_V8_MEMORY = (6 << 6), + RTYPE_WRITE_V8_MEMORY = (7 << 6), + RTYPE_WRITE_V8_FLASH = (8 << 6), + RTYPE_GENERIC = (9 << 6), +} b2c2_usb_request_type_t; + +/* request */ +typedef enum { + B2C2_USB_WRITE_V8_MEM = 0x04, + B2C2_USB_READ_V8_MEM = 0x05, + B2C2_USB_READ_REG = 0x08, + B2C2_USB_WRITE_REG = 0x0A, +/* B2C2_USB_WRITEREGLO = 0x0A, */ + B2C2_USB_WRITEREGHI = 0x0B, + B2C2_USB_FLASH_BLOCK = 0x10, + B2C2_USB_I2C_REQUEST = 0x11, + B2C2_USB_UTILITY = 0x12, +} b2c2_usb_request_t; + +/* function definition for I2C_REQUEST */ +typedef enum { + USB_FUNC_I2C_WRITE = 0x01, + USB_FUNC_I2C_MULTIWRITE = 0x02, + USB_FUNC_I2C_READ = 0x03, + USB_FUNC_I2C_REPEATWRITE = 0x04, + USB_FUNC_GET_DESCRIPTOR = 0x05, + USB_FUNC_I2C_REPEATREAD = 0x06, +/* DKT 020208 - add this to support special case of DiSEqC */ + USB_FUNC_I2C_CHECKWRITE = 0x07, + USB_FUNC_I2C_CHECKRESULT = 0x08, +} b2c2_usb_i2c_function_t; + +/* + * function definition for UTILITY request 0x12 + * DKT 020304 - new utility function + */ +typedef enum { + UTILITY_SET_FILTER = 0x01, + UTILITY_DATA_ENABLE = 0x02, + UTILITY_FLEX_MULTIWRITE = 0x03, + UTILITY_SET_BUFFER_SIZE = 0x04, + UTILITY_FLEX_OPERATOR = 0x05, + UTILITY_FLEX_RESET300_START = 0x06, + UTILITY_FLEX_RESET300_STOP = 0x07, + UTILITY_FLEX_RESET300 = 0x08, + UTILITY_SET_ISO_SIZE = 0x09, + UTILITY_DATA_RESET = 0x0A, + UTILITY_GET_DATA_STATUS = 0x10, + UTILITY_GET_V8_REG = 0x11, +/* DKT 020326 - add function for v1.14 */ + UTILITY_SRAM_WRITE = 0x12, + UTILITY_SRAM_READ = 0x13, + UTILITY_SRAM_TESTFILL = 0x14, + UTILITY_SRAM_TESTSET = 0x15, + UTILITY_SRAM_TESTVERIFY = 0x16, +} b2c2_usb_utility_function_t; + +#define B2C2_WAIT_FOR_OPERATION_RW 1 // 1 s +#define B2C2_WAIT_FOR_OPERATION_RDW 3 // 3 s +#define B2C2_WAIT_FOR_OPERATION_WDW 1 // 1 s + +#define B2C2_WAIT_FOR_OPERATION_V8READ 3 // 3 s +#define B2C2_WAIT_FOR_OPERATION_V8WRITE 3 // 3 s +#define B2C2_WAIT_FOR_OPERATION_V8FLASH 3 // 3 s + +/* JLP 111700: we will include the 1 bit gap between the upper and lower 3 bits + * in the IBI address, to make the V8 code simpler. + * PCI ADDRESS FORMAT: 0x71C -> 0000 0111 0001 1100 (these are the six bits used) + * in general: 0000 0HHH 000L LL00 + * IBI ADDRESS FORMAT: RHHH BLLL + * + * where R is the read(1)/write(0) bit, B is the busy bit + * and HHH and LLL are the two sets of three bits from the PCI address. + */ +#define B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(usPCI) (u8) (((usPCI >> 2) & 0x07) + ((usPCI >> 4) & 0x70)) +#define B2C2_FLEX_INTERNALADDR_TO_PCIOFFSET(ucAddr) (u16) (((ucAddr & 0x07) << 2) + ((ucAddr & 0x70) << 4)) + +/* + * DKT 020228 - forget about this VENDOR_BUFFER_SIZE, read and write register + * deal with DWORD or 4 bytes, that should be should from now on + */ +static u32 b2c2_usb_read_dw(struct usb_b2c2_usb *b2c2, u16 wRegOffsPCI) +{ + u32 val; + u16 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI) | 0x0080; + int len = usb_control_msg(b2c2->udev, + B2C2_USB_CTRL_PIPE_IN, + B2C2_USB_READ_REG, + RTYPE_READ_DW, + wAddress, + 0, + &val, + sizeof(u32), + B2C2_WAIT_FOR_OPERATION_RDW * HZ); + + if (len != sizeof(u32)) { + err("error while reading dword from %d (%d).",wAddress,wRegOffsPCI); + return -EIO; + } else + return val; +} + +/* + * DKT 020228 - from now on, we don't support anything older than firm 1.00 + * I eliminated the write register as a 2 trip of writing hi word and lo word + * and force this to write only 4 bytes at a time. + * NOTE: this should work with all the firmware from 1.00 and newer + */ +static int b2c2_usb_write_dw(struct usb_b2c2_usb *b2c2, u16 wRegOffsPCI, u32 val) +{ + u16 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI); + int len = usb_control_msg(b2c2->udev, + B2C2_USB_CTRL_PIPE_OUT, + B2C2_USB_WRITE_REG, + RTYPE_WRITE_DW_1, + wAddress, + 0, + &val, + sizeof(u32), + B2C2_WAIT_FOR_OPERATION_RDW * HZ); + + if (len != sizeof(u32)) { + err("error while reading dword from %d (%d).",wAddress,wRegOffsPCI); + return -EIO; + } else + return 0; +} + +/* + * DKT 010817 - add support for V8 memory read/write and flash update + */ +static int b2c2_usb_v8_memory_req(struct usb_b2c2_usb *b2c2, + b2c2_usb_request_t req, u8 page, u16 wAddress, + u16 buflen, u8 *pbBuffer) +{ + u8 dwRequestType; + u16 wIndex; + int nWaitTime,pipe,len; + + wIndex = page << 8; + + switch (req) { + case B2C2_USB_READ_V8_MEM: + nWaitTime = B2C2_WAIT_FOR_OPERATION_V8READ; + dwRequestType = (u8) RTYPE_READ_V8_MEMORY; + pipe = B2C2_USB_CTRL_PIPE_IN; + break; + case B2C2_USB_WRITE_V8_MEM: + wIndex |= pbBuffer[0]; + nWaitTime = B2C2_WAIT_FOR_OPERATION_V8WRITE; + dwRequestType = (u8) RTYPE_WRITE_V8_MEMORY; + pipe = B2C2_USB_CTRL_PIPE_OUT; + break; + case B2C2_USB_FLASH_BLOCK: + nWaitTime = B2C2_WAIT_FOR_OPERATION_V8FLASH; + dwRequestType = (u8) RTYPE_WRITE_V8_FLASH; + pipe = B2C2_USB_CTRL_PIPE_OUT; + break; + default: + deb_info("unsupported request for v8_mem_req %x.\n",req); + return -EINVAL; + } + len = usb_control_msg(b2c2->udev,pipe, + req, + dwRequestType, + wAddress, + wIndex, + pbBuffer, + buflen, + nWaitTime * HZ); + return len == buflen ? 0 : -EIO; +} + +static int b2c2_usb_i2c_req(struct usb_b2c2_usb *b2c2, + b2c2_usb_request_t req, b2c2_usb_i2c_function_t func, + u8 port, u8 chipaddr, u8 addr, u8 buflen, u8 *buf) +{ + u16 wValue, wIndex; + int nWaitTime,pipe,len; + u8 dwRequestType; + + switch (func) { + case USB_FUNC_I2C_WRITE: + case USB_FUNC_I2C_MULTIWRITE: + case USB_FUNC_I2C_REPEATWRITE: + /* DKT 020208 - add this to support special case of DiSEqC */ + case USB_FUNC_I2C_CHECKWRITE: + pipe = B2C2_USB_CTRL_PIPE_OUT; + nWaitTime = 2; + dwRequestType = (u8) RTYPE_GENERIC; + break; + case USB_FUNC_I2C_READ: + case USB_FUNC_I2C_REPEATREAD: + pipe = B2C2_USB_CTRL_PIPE_IN; + nWaitTime = 2; + dwRequestType = (u8) RTYPE_GENERIC; + break; + default: + deb_info("unsupported function for i2c_req %x\n",func); + return -EINVAL; + } + wValue = (func << 8 ) | port; + wIndex = (chipaddr << 8 ) | addr; + + len = usb_control_msg(b2c2->udev,pipe, + req, + dwRequestType, + addr, + wIndex, + buf, + buflen, + nWaitTime * HZ); + return len == buflen ? 0 : -EIO; +} + +int static b2c2_usb_utility_req(struct usb_b2c2_usb *b2c2, int set, + b2c2_usb_utility_function_t func, u8 extra, u16 wIndex, + u16 buflen, u8 *pvBuffer) +{ + u16 wValue; + int nWaitTime = 2, + pipe = set ? B2C2_USB_CTRL_PIPE_OUT : B2C2_USB_CTRL_PIPE_IN, + len; + + wValue = (func << 8) | extra; + + len = usb_control_msg(b2c2->udev,pipe, + B2C2_USB_UTILITY, + (u8) RTYPE_GENERIC, + wValue, + wIndex, + pvBuffer, + buflen, + nWaitTime * HZ); + return len == buflen ? 0 : -EIO; +} + + + +static void b2c2_dumpfourreg(struct usb_b2c2_usb *b2c2, u16 offs) +{ + u32 r0,r1,r2,r3; + r0 = r1 = r2 = r3 = 0; + r0 = b2c2_usb_read_dw(b2c2,offs); + r1 = b2c2_usb_read_dw(b2c2,offs + 0x04); + r2 = b2c2_usb_read_dw(b2c2,offs + 0x08); + r3 = b2c2_usb_read_dw(b2c2,offs + 0x0c); + deb_ctrl("dump: offset: %03x, %08x, %08x, %08x, %08x\n",offs,r0,r1,r2,r3); +} + +static void b2c2_urb_complete(struct urb *urb, struct pt_regs *ptregs) +{ + struct usb_b2c2_usb *b2c2 = urb->context; + deb_ts("urb completed, bufsize: %d\n",urb->transfer_buffer_length); + +// urb_submit_urb(urb,GFP_ATOMIC); enable for real action +} + +static void b2c2_exit_usb(struct usb_b2c2_usb *b2c2) +{ + int i; + for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) + if (b2c2->iso_urb[i] != NULL) { /* not sure about unlink_urb and iso-urbs TODO */ + deb_info("unlinking/killing urb no. %d\n",i); +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,7) + usb_unlink_urb(b2c2->iso_urb[i]); +#else + usb_kill_urb(b2c2->iso_urb[i]); +#endif + usb_free_urb(b2c2->iso_urb[i]); + } + + if (b2c2->iso_buffer != NULL) + pci_free_consistent(NULL,b2c2->buffer_size, b2c2->iso_buffer, b2c2->iso_dma_handle); + +} + +static int b2c2_init_usb(struct usb_b2c2_usb *b2c2) +{ + u16 frame_size = b2c2->uintf->cur_altsetting->endpoint[0].desc.wMaxPacketSize; + int bufsize = B2C2_USB_NUM_ISO_URB * B2C2_USB_FRAMES_PER_ISO * frame_size,i,j,ret; + int buffer_offset = 0; + + deb_info("creating %d iso-urbs with %d frames each of %d bytes size = %d.\n", + B2C2_USB_NUM_ISO_URB, B2C2_USB_FRAMES_PER_ISO, frame_size,bufsize); + + b2c2->iso_buffer = pci_alloc_consistent(NULL,bufsize,&b2c2->iso_dma_handle); + if (b2c2->iso_buffer == NULL) + return -ENOMEM; + memset(b2c2->iso_buffer, 0, bufsize); + b2c2->buffer_size = bufsize; + + /* creating iso urbs */ + for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) + if (!(b2c2->iso_urb[i] = usb_alloc_urb(B2C2_USB_FRAMES_PER_ISO,GFP_ATOMIC))) { + ret = -ENOMEM; + goto urb_error; + } + /* initialising and submitting iso urbs */ + for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) { + deb_info("initializing and submitting urb no. %d (buf_offset: %d).\n",i,buffer_offset); + int frame_offset = 0; + struct urb *urb = b2c2->iso_urb[i]; + + urb->dev = b2c2->udev; + urb->context = b2c2; + urb->complete = b2c2_urb_complete; + urb->pipe = B2C2_USB_DATA_PIPE; + urb->transfer_flags = URB_ISO_ASAP; + urb->interval = 1; + urb->number_of_packets = B2C2_USB_FRAMES_PER_ISO; + urb->transfer_buffer_length = frame_size * B2C2_USB_FRAMES_PER_ISO; + urb->transfer_buffer = b2c2->iso_buffer + buffer_offset; + + buffer_offset += frame_size * B2C2_USB_FRAMES_PER_ISO; + for (j = 0; j < B2C2_USB_FRAMES_PER_ISO; j++) { + deb_info("urb no: %d, frame: %d, frame_offset: %d\n",i,j,frame_offset); + urb->iso_frame_desc[j].offset = frame_offset; + urb->iso_frame_desc[j].length = frame_size; + frame_offset += frame_size; + } + + if ((ret = usb_submit_urb(b2c2->iso_urb[i],GFP_ATOMIC))) { + err("submitting urb %d failed with %d.",i,ret); + goto urb_error; + } + deb_info("submitted urb no. %d.\n",i); + } + + ret = 0; + goto success; +urb_error: + b2c2_exit_usb(b2c2); +success: + return ret; +} + +static int b2c2_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct usb_b2c2_usb *b2c2 = NULL; + int ret; + + b2c2 = kmalloc(sizeof(struct usb_b2c2_usb),GFP_KERNEL); + if (b2c2 == NULL) { + err("no memory"); + return -ENOMEM; + } + b2c2->udev = udev; + b2c2->uintf = intf; + + /* use the alternate setting with the larges buffer */ + usb_set_interface(udev,0,1); + + if ((ret = b2c2_init_usb(b2c2))) + goto usb_init_error; + + usb_set_intfdata(intf,b2c2); + + switch (udev->speed) { + case USB_SPEED_LOW: + err("cannot handle USB speed because it is to sLOW."); + break; + case USB_SPEED_FULL: + info("running at FULL speed."); + break; + case USB_SPEED_HIGH: + info("running at HIGH speed."); + break; + case USB_SPEED_UNKNOWN: /* fall through */ + default: + err("cannot handle USB speed because it is unkown."); + break; + } + + b2c2_dumpfourreg(b2c2,0x200); + b2c2_dumpfourreg(b2c2,0x300); + b2c2_dumpfourreg(b2c2,0x400); + b2c2_dumpfourreg(b2c2,0x700); + + + if (ret == 0) + info("%s successfully initialized and connected.",DRIVER_DESC); + else + info("%s error while loading driver (%d)",DRIVER_DESC,ret); + + ret = 0; + goto success; + +usb_init_error: + kfree(b2c2); +success: + return ret; +} + +static void b2c2_usb_disconnect(struct usb_interface *intf) +{ + struct usb_b2c2_usb *b2c2 = usb_get_intfdata(intf); + usb_set_intfdata(intf,NULL); + if (b2c2 != NULL) { + b2c2_exit_usb(b2c2); + kfree(b2c2); + } + info("%s successfully deinitialized and disconnected.",DRIVER_DESC); + +} + +static struct usb_device_id b2c2_usb_table [] = { + { USB_DEVICE(0x0af7, 0x0101) } +}; + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver b2c2_usb_driver = { + .owner = THIS_MODULE, + .name = "dvb_b2c2_usb", + .probe = b2c2_usb_probe, + .disconnect = b2c2_usb_disconnect, + .id_table = b2c2_usb_table, +}; + +/* module stuff */ +static int __init b2c2_usb_init(void) +{ + int result; + if ((result = usb_register(&b2c2_usb_driver))) { + err("usb_register failed. Error number %d",result); + return result; + } + + return 0; +} + +static void __exit b2c2_usb_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&b2c2_usb_driver); +} + +module_init (b2c2_usb_init); +module_exit (b2c2_usb_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff -puN drivers/media/dvb/b2c2/Kconfig~dvb-b2c2-driver-splitup drivers/media/dvb/b2c2/Kconfig --- 25/drivers/media/dvb/b2c2/Kconfig~dvb-b2c2-driver-splitup Fri Dec 10 15:14:12 2004 +++ 25-akpm/drivers/media/dvb/b2c2/Kconfig Fri Dec 10 15:14:12 2004 @@ -1,10 +1,24 @@ config DVB_B2C2_SKYSTAR - tristate "Technisat Skystar2 PCI" + tristate "B2C2/Technisat Air/Sky/CableStar 2 PCI" depends on DVB_CORE && PCI select DVB_STV0299 select DVB_MT352 + select DVB_MT312 help Support for the Skystar2 PCI DVB card by Technisat, which is equipped with the FlexCopII chipset by B2C2. Say Y if you own such a device and want to use it. + +config DVB_B2C2_USB + tristate "B2C2/Technisat Air/Sky/Cable2PC USB" + depends on DVB_CORE && USB && EXPERIMENTAL + select DVB_STV0299 + select DVB_MT352 + help + Support for the Air/Sky/Cable2PC USB DVB device by B2C2. Currently + this does nothing, but providing basic function for the used usb + protocol. + + Say Y if you own such a device and want to use it. + diff -puN drivers/media/dvb/b2c2/Makefile~dvb-b2c2-driver-splitup drivers/media/dvb/b2c2/Makefile --- 25/drivers/media/dvb/b2c2/Makefile~dvb-b2c2-driver-splitup Fri Dec 10 15:14:12 2004 +++ 25-akpm/drivers/media/dvb/b2c2/Makefile Fri Dec 10 15:14:12 2004 @@ -1,3 +1,6 @@ +obj-b2c2-usb = b2c2-usb-core.o b2c2-common.o + obj-$(CONFIG_DVB_B2C2_SKYSTAR) += skystar2.o +obj-$(CONFIG_DVB_B2C2_USB) + = b2c2-usb.o EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ diff -puN drivers/media/dvb/b2c2/skystar2.c~dvb-b2c2-driver-splitup drivers/media/dvb/b2c2/skystar2.c --- 25/drivers/media/dvb/b2c2/skystar2.c~dvb-b2c2-driver-splitup Fri Dec 10 15:14:12 2004 +++ 25-akpm/drivers/media/dvb/b2c2/skystar2.c Fri Dec 10 15:14:12 2004 @@ -52,6 +52,7 @@ #include "dvb_net.h" #include "stv0299.h" #include "mt352.h" +#include "mt312.h" static int debug; @@ -315,10 +316,10 @@ static int master_xfer(struct i2c_adapte up(&tmp->i2c_sem); if (ret != msgs[1].len) { - printk("%s: read error !\n", __FUNCTION__); + dprintk("%s: read error !\n", __FUNCTION__); for (i = 0; i < 2; i++) { - printk("message %d: flags=0x%x, addr=0x%x, buf=0x%x, len=%d \n", i, + dprintk("message %d: flags=0x%x, addr=0x%x, buf=0x%x, len=%d \n", i, msgs[i].flags, msgs[i].addr, msgs[i].buf[0], msgs[i].len); } @@ -338,9 +339,9 @@ static int master_xfer(struct i2c_adapte up(&tmp->i2c_sem); if (ret != msgs[0].len - 1) { - printk("%s: write error %i !\n", __FUNCTION__, ret); + dprintk("%s: write error %i !\n", __FUNCTION__, ret); - printk("message %d: flags=0x%x, addr=0x%x, buf[0]=0x%x, len=%d \n", i, + dprintk("message %d: flags=0x%x, addr=0x%x, buf[0]=0x%x, len=%d \n", i, msgs[i].flags, msgs[i].addr, msgs[i].buf[0], msgs[i].len); return -EREMOTEIO; @@ -2026,7 +2027,6 @@ static int dvb_stop_feed(struct dvb_demu return 0; } -#if 0 /* lnb control */ static void set_tuner_tone(struct adapter *adapter, u8 tone) { @@ -2061,7 +2061,6 @@ static void set_tuner_tone(struct adapte write_reg_dw(adapter, 0x200, 0x40ff8000); } } -#endif static void set_tuner_polarity(struct adapter *adapter, u8 polarity) { @@ -2089,7 +2088,6 @@ static void set_tuner_polarity(struct ad write_reg_dw(adapter, 0x204, var); } -#if 0 static void diseqc_send_bit(struct adapter *adapter, int data) { set_tuner_tone(adapter, 1); @@ -2139,12 +2137,11 @@ static int send_diseqc_msg(struct adapte return 0; } - -static int soft_diseqc(struct adapter *adapter, unsigned int cmd, void *arg) +static int flexcop_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) { - switch (cmd) { - case FE_SET_TONE: - switch ((fe_sec_tone_mode_t) arg) { + struct adapter* adapter = (struct adapter*) fe->dvb->priv; + + switch(tone) { case SEC_TONE_ON: set_tuner_tone(adapter, 1); break; @@ -2154,27 +2151,27 @@ static int soft_diseqc(struct adapter *a default: return -EINVAL; }; - break; - case FE_DISEQC_SEND_MASTER_CMD: + return 0; +} + +static int flexcop_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) { - struct dvb_diseqc_master_cmd *cmd = arg; + struct adapter* adapter = (struct adapter*) fe->dvb->priv; send_diseqc_msg(adapter, cmd->msg_len, cmd->msg, 0); - break; + + return 0; } - case FE_DISEQC_SEND_BURST: - send_diseqc_msg(adapter, 0, NULL, (unsigned long) arg); - break; +static int flexcop_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) +{ + struct adapter* adapter = (struct adapter*) fe->dvb->priv; - default: - return -EOPNOTSUPP; - }; + send_diseqc_msg(adapter, 0, NULL, minicmd); return 0; } -#endif static int flexcop_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) { @@ -2377,6 +2374,32 @@ static struct mt352_config samsung_tdtc9 .pll_set = samsung_tdtc9251dh0_pll_set, }; +static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + u8 buf[4]; + u32 div; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; + struct adapter* adapter = (struct adapter*) fe->dvb->priv; + + div = (params->frequency + (125/2)) / 125; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = (div >> 0) & 0xff; + buf[2] = 0x84 | ((div >> 10) & 0x60); + buf[3] = 0x80; + + if (params->frequency < 1550000) + buf[3] |= 0x02; + + if (i2c_transfer (&adapter->i2c_adap, &msg, 1) != 1) return -EIO; + return 0; +} + +static struct mt312_config skystar23_samsung_tbdu18132_config = { + + .demod_address = 0x0e, + .pll_set = skystar23_samsung_tbdu18132_pll_set, +}; @@ -2386,7 +2409,7 @@ static void frontend_init(struct adapter switch(skystar2->pdev->device) { case 0x2103: // Technisat Skystar2 OR Technisat Airstar2 - // try the skystar2 first (stv0299/Samsung tbmu24112(sl1935)) + // try the skystar2 v2.6 first (stv0299/Samsung tbmu24112(sl1935)) skystar2->fe = stv0299_attach(&samsung_tbmu24112_config, &skystar2->i2c_adap); if (skystar2->fe != NULL) { skystar2->fe->ops->set_voltage = flexcop_set_voltage; @@ -2402,6 +2425,18 @@ static void frontend_init(struct adapter skystar2->fe->ops->info.frequency_max = 858000000; break; } + + // try the skystar2 v2.3 (vp310/Samsung tbdu18132(tsa5059)) + skystar2->fe = vp310_attach(&skystar23_samsung_tbdu18132_config, &skystar2->i2c_adap); + if (skystar2->fe != NULL) { + skystar2->fe->ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd; + skystar2->fe->ops->diseqc_send_burst = flexcop_diseqc_send_burst; + skystar2->fe->ops->set_tone = flexcop_set_tone; + skystar2->fe->ops->set_voltage = flexcop_set_voltage; + skystar2->fe_sleep = skystar2->fe->ops->sleep; + skystar2->fe->ops->sleep = flexcop_sleep; + break; + } break; } _