kernel-ark/drivers/staging/go7007/go7007-usb.c
Jean Delvare 7400516ab4 go7007: Convert to the new i2c device binding model
Move the go7007 driver away from the legacy i2c binding model, which
is going away really soon now.

The I2C addresses of the audio and video chips in s2250-board didn't
look quite right, apparently they were left-aligned values when Linux
wants right-aligned values, so I fixed them too.

Signed-off-by: Jean Delvare <khali@linux-fr.org>
Cc: Greg Kroah-Hartman <gregkh@suse.de>
2009-04-21 21:47:22 +02:00

1288 lines
34 KiB
C

/*
* Copyright (C) 2005-2006 Micronas USA Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* 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., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/wait.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/mm.h>
#include <linux/usb.h>
#include <linux/i2c.h>
#include <asm/byteorder.h>
#include <media/tvaudio.h>
#include "go7007-priv.h"
#include "wis-i2c.h"
static unsigned int assume_endura;
module_param(assume_endura, int, 0644);
MODULE_PARM_DESC(assume_endura, "when probing fails, hardware is a Pelco Endura");
/* #define GO7007_USB_DEBUG */
/* #define GO7007_I2C_DEBUG */ /* for debugging the EZ-USB I2C adapter */
#define HPI_STATUS_ADDR 0xFFF4
#define INT_PARAM_ADDR 0xFFF6
#define INT_INDEX_ADDR 0xFFF8
/*
* Pipes on EZ-USB interface:
* 0 snd - Control
* 0 rcv - Control
* 2 snd - Download firmware (control)
* 4 rcv - Read Interrupt (interrupt)
* 6 rcv - Read Video (bulk)
* 8 rcv - Read Audio (bulk)
*/
#define GO7007_USB_EZUSB (1<<0)
#define GO7007_USB_EZUSB_I2C (1<<1)
struct go7007_usb_board {
unsigned int flags;
struct go7007_board_info main_info;
};
struct go7007_usb {
struct go7007_usb_board *board;
struct semaphore i2c_lock;
struct usb_device *usbdev;
struct urb *video_urbs[8];
struct urb *audio_urbs[8];
struct urb *intr_urb;
};
/*********************** Product specification data ***********************/
static struct go7007_usb_board board_matrix_ii = {
.flags = GO7007_USB_EZUSB,
.main_info = {
.firmware = "go7007tv.bin",
.flags = GO7007_BOARD_HAS_AUDIO |
GO7007_BOARD_USE_ONBOARD_I2C,
.audio_flags = GO7007_AUDIO_I2S_MODE_1 |
GO7007_AUDIO_WORD_16,
.audio_rate = 48000,
.audio_bclk_div = 8,
.audio_main_div = 2,
.hpi_buffer_cap = 7,
.sensor_flags = GO7007_SENSOR_656 |
GO7007_SENSOR_VALID_ENABLE |
GO7007_SENSOR_TV |
GO7007_SENSOR_VBI |
GO7007_SENSOR_SCALING,
.num_i2c_devs = 1,
.i2c_devs = {
{
.type = "wis_saa7115",
.id = I2C_DRIVERID_WIS_SAA7115,
.addr = 0x20,
},
},
.num_inputs = 2,
.inputs = {
{
.video_input = 0,
.name = "Composite",
},
{
.video_input = 9,
.name = "S-Video",
},
},
},
};
static struct go7007_usb_board board_matrix_reload = {
.flags = GO7007_USB_EZUSB,
.main_info = {
.firmware = "go7007tv.bin",
.flags = GO7007_BOARD_HAS_AUDIO |
GO7007_BOARD_USE_ONBOARD_I2C,
.audio_flags = GO7007_AUDIO_I2S_MODE_1 |
GO7007_AUDIO_I2S_MASTER |
GO7007_AUDIO_WORD_16,
.audio_rate = 48000,
.audio_bclk_div = 8,
.audio_main_div = 2,
.hpi_buffer_cap = 7,
.sensor_flags = GO7007_SENSOR_656 |
GO7007_SENSOR_TV,
.num_i2c_devs = 1,
.i2c_devs = {
{
.type = "wis_saa7113",
.id = I2C_DRIVERID_WIS_SAA7113,
.addr = 0x25,
},
},
.num_inputs = 2,
.inputs = {
{
.video_input = 0,
.name = "Composite",
},
{
.video_input = 9,
.name = "S-Video",
},
},
},
};
static struct go7007_usb_board board_star_trek = {
.flags = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C,
.main_info = {
.firmware = "go7007tv.bin",
.flags = GO7007_BOARD_HAS_AUDIO, /* |
GO7007_BOARD_HAS_TUNER, */
.sensor_flags = GO7007_SENSOR_656 |
GO7007_SENSOR_VALID_ENABLE |
GO7007_SENSOR_TV |
GO7007_SENSOR_VBI |
GO7007_SENSOR_SCALING,
.audio_flags = GO7007_AUDIO_I2S_MODE_1 |
GO7007_AUDIO_WORD_16,
.audio_bclk_div = 8,
.audio_main_div = 2,
.hpi_buffer_cap = 7,
.num_i2c_devs = 1,
.i2c_devs = {
{
.type = "wis_saa7115",
.id = I2C_DRIVERID_WIS_SAA7115,
.addr = 0x20,
},
},
.num_inputs = 2,
.inputs = {
{
.video_input = 1,
/* .audio_input = AUDIO_EXTERN, */
.name = "Composite",
},
{
.video_input = 8,
/* .audio_input = AUDIO_EXTERN, */
.name = "S-Video",
},
/* {
* .video_input = 3,
* .audio_input = AUDIO_TUNER,
* .name = "Tuner",
* },
*/
},
},
};
static struct go7007_usb_board board_px_tv402u = {
.flags = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C,
.main_info = {
.firmware = "go7007tv.bin",
.flags = GO7007_BOARD_HAS_AUDIO |
GO7007_BOARD_HAS_TUNER,
.sensor_flags = GO7007_SENSOR_656 |
GO7007_SENSOR_VALID_ENABLE |
GO7007_SENSOR_TV |
GO7007_SENSOR_VBI |
GO7007_SENSOR_SCALING,
.audio_flags = GO7007_AUDIO_I2S_MODE_1 |
GO7007_AUDIO_WORD_16,
.audio_bclk_div = 8,
.audio_main_div = 2,
.hpi_buffer_cap = 7,
.num_i2c_devs = 3,
.i2c_devs = {
{
.type = "wis_saa7115",
.id = I2C_DRIVERID_WIS_SAA7115,
.addr = 0x20,
},
{
.type = "wis_uda1342",
.id = I2C_DRIVERID_WIS_UDA1342,
.addr = 0x1a,
},
{
.type = "wis_sony_tuner",
.id = I2C_DRIVERID_WIS_SONY_TUNER,
.addr = 0x60,
},
},
.num_inputs = 3,
.inputs = {
{
.video_input = 1,
.audio_input = TVAUDIO_INPUT_EXTERN,
.name = "Composite",
},
{
.video_input = 8,
.audio_input = TVAUDIO_INPUT_EXTERN,
.name = "S-Video",
},
{
.video_input = 3,
.audio_input = TVAUDIO_INPUT_TUNER,
.name = "Tuner",
},
},
},
};
static struct go7007_usb_board board_xmen = {
.flags = 0,
.main_info = {
.firmware = "go7007tv.bin",
.flags = GO7007_BOARD_USE_ONBOARD_I2C,
.hpi_buffer_cap = 0,
.sensor_flags = GO7007_SENSOR_VREF_POLAR,
.sensor_width = 320,
.sensor_height = 240,
.sensor_framerate = 30030,
.audio_flags = GO7007_AUDIO_ONE_CHANNEL |
GO7007_AUDIO_I2S_MODE_3 |
GO7007_AUDIO_WORD_14 |
GO7007_AUDIO_I2S_MASTER |
GO7007_AUDIO_BCLK_POLAR |
GO7007_AUDIO_OKI_MODE,
.audio_rate = 8000,
.audio_bclk_div = 48,
.audio_main_div = 1,
.num_i2c_devs = 1,
.i2c_devs = {
{
.type = "wis_ov7640",
.id = I2C_DRIVERID_WIS_OV7640,
.addr = 0x21,
},
},
.num_inputs = 1,
.inputs = {
{
.name = "Camera",
},
},
},
};
static struct go7007_usb_board board_matrix_revolution = {
.flags = GO7007_USB_EZUSB,
.main_info = {
.firmware = "go7007tv.bin",
.flags = GO7007_BOARD_HAS_AUDIO |
GO7007_BOARD_USE_ONBOARD_I2C,
.audio_flags = GO7007_AUDIO_I2S_MODE_1 |
GO7007_AUDIO_I2S_MASTER |
GO7007_AUDIO_WORD_16,
.audio_rate = 48000,
.audio_bclk_div = 8,
.audio_main_div = 2,
.hpi_buffer_cap = 7,
.sensor_flags = GO7007_SENSOR_656 |
GO7007_SENSOR_TV |
GO7007_SENSOR_VBI,
.num_i2c_devs = 1,
.i2c_devs = {
{
.type = "wis_tw9903",
.id = I2C_DRIVERID_WIS_TW9903,
.addr = 0x44,
},
},
.num_inputs = 2,
.inputs = {
{
.video_input = 2,
.name = "Composite",
},
{
.video_input = 8,
.name = "S-Video",
},
},
},
};
static struct go7007_usb_board board_lifeview_lr192 = {
.flags = GO7007_USB_EZUSB,
.main_info = {
.firmware = "go7007tv.bin",
.flags = GO7007_BOARD_HAS_AUDIO |
GO7007_BOARD_USE_ONBOARD_I2C,
.audio_flags = GO7007_AUDIO_I2S_MODE_1 |
GO7007_AUDIO_WORD_16,
.audio_rate = 48000,
.audio_bclk_div = 8,
.audio_main_div = 2,
.hpi_buffer_cap = 7,
.sensor_flags = GO7007_SENSOR_656 |
GO7007_SENSOR_VALID_ENABLE |
GO7007_SENSOR_TV |
GO7007_SENSOR_VBI |
GO7007_SENSOR_SCALING,
.num_i2c_devs = 0,
.num_inputs = 1,
.inputs = {
{
.video_input = 0,
.name = "Composite",
},
},
},
};
static struct go7007_usb_board board_endura = {
.flags = 0,
.main_info = {
.firmware = "go7007tv.bin",
.flags = 0,
.audio_flags = GO7007_AUDIO_I2S_MODE_1 |
GO7007_AUDIO_I2S_MASTER |
GO7007_AUDIO_WORD_16,
.audio_rate = 8000,
.audio_bclk_div = 48,
.audio_main_div = 8,
.hpi_buffer_cap = 0,
.sensor_flags = GO7007_SENSOR_656 |
GO7007_SENSOR_TV,
.sensor_h_offset = 8,
.num_i2c_devs = 0,
.num_inputs = 1,
.inputs = {
{
.name = "Camera",
},
},
},
};
static struct go7007_usb_board board_adlink_mpg24 = {
.flags = 0,
.main_info = {
.firmware = "go7007tv.bin",
.flags = GO7007_BOARD_USE_ONBOARD_I2C,
.audio_flags = GO7007_AUDIO_I2S_MODE_1 |
GO7007_AUDIO_I2S_MASTER |
GO7007_AUDIO_WORD_16,
.audio_rate = 48000,
.audio_bclk_div = 8,
.audio_main_div = 2,
.hpi_buffer_cap = 0,
.sensor_flags = GO7007_SENSOR_656 |
GO7007_SENSOR_TV |
GO7007_SENSOR_VBI,
.num_i2c_devs = 1,
.i2c_devs = {
{
.type = "wis_twTW2804",
.id = I2C_DRIVERID_WIS_TW2804,
.addr = 0x00, /* yes, really */
},
},
.num_inputs = 1,
.inputs = {
{
.name = "Composite",
},
},
},
};
static struct go7007_usb_board board_sensoray_2250 = {
.flags = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C,
.main_info = {
.firmware = "go7007tv.bin",
.audio_flags = GO7007_AUDIO_I2S_MODE_1 |
GO7007_AUDIO_I2S_MASTER |
GO7007_AUDIO_WORD_16,
.flags = GO7007_BOARD_HAS_AUDIO,
.audio_rate = 48000,
.audio_bclk_div = 8,
.audio_main_div = 2,
.hpi_buffer_cap = 7,
.sensor_flags = GO7007_SENSOR_656 |
GO7007_SENSOR_TV,
.num_i2c_devs = 1,
.i2c_devs = {
{
.type = "s2250_board",
.id = I2C_DRIVERID_S2250,
.addr = 0x43,
},
},
.num_inputs = 2,
.inputs = {
{
.video_input = 0,
.name = "Composite",
},
{
.video_input = 1,
.name = "S-Video",
},
},
},
};
static struct usb_device_id go7007_usb_id_table[] = {
{
.match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION |
USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */
.idProduct = 0x7007, /* Product ID of GO7007SB chip */
.bcdDevice_lo = 0x200, /* Revision number of XMen */
.bcdDevice_hi = 0x200,
.bInterfaceClass = 255,
.bInterfaceSubClass = 0,
.bInterfaceProtocol = 255,
.driver_info = (kernel_ulong_t)GO7007_BOARDID_XMEN,
},
{
.match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
.idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */
.idProduct = 0x7007, /* Product ID of GO7007SB chip */
.bcdDevice_lo = 0x202, /* Revision number of Matrix II */
.bcdDevice_hi = 0x202,
.driver_info = (kernel_ulong_t)GO7007_BOARDID_MATRIX_II,
},
{
.match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
.idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */
.idProduct = 0x7007, /* Product ID of GO7007SB chip */
.bcdDevice_lo = 0x204, /* Revision number of Matrix */
.bcdDevice_hi = 0x204, /* Reloaded */
.driver_info = (kernel_ulong_t)GO7007_BOARDID_MATRIX_RELOAD,
},
{
.match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION |
USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */
.idProduct = 0x7007, /* Product ID of GO7007SB chip */
.bcdDevice_lo = 0x205, /* Revision number of XMen-II */
.bcdDevice_hi = 0x205,
.bInterfaceClass = 255,
.bInterfaceSubClass = 0,
.bInterfaceProtocol = 255,
.driver_info = (kernel_ulong_t)GO7007_BOARDID_XMEN_II,
},
{
.match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
.idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */
.idProduct = 0x7007, /* Product ID of GO7007SB chip */
.bcdDevice_lo = 0x208, /* Revision number of Star Trek */
.bcdDevice_hi = 0x208,
.driver_info = (kernel_ulong_t)GO7007_BOARDID_STAR_TREK,
},
{
.match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION |
USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */
.idProduct = 0x7007, /* Product ID of GO7007SB chip */
.bcdDevice_lo = 0x209, /* Revision number of XMen-III */
.bcdDevice_hi = 0x209,
.bInterfaceClass = 255,
.bInterfaceSubClass = 0,
.bInterfaceProtocol = 255,
.driver_info = (kernel_ulong_t)GO7007_BOARDID_XMEN_III,
},
{
.match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
.idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */
.idProduct = 0x7007, /* Product ID of GO7007SB chip */
.bcdDevice_lo = 0x210, /* Revision number of Matrix */
.bcdDevice_hi = 0x210, /* Revolution */
.driver_info = (kernel_ulong_t)GO7007_BOARDID_MATRIX_REV,
},
{
.match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
.idVendor = 0x093b, /* Vendor ID of Plextor */
.idProduct = 0xa102, /* Product ID of M402U */
.bcdDevice_lo = 0x1, /* revision number of Blueberry */
.bcdDevice_hi = 0x1,
.driver_info = (kernel_ulong_t)GO7007_BOARDID_PX_M402U,
},
{
.match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
.idVendor = 0x093b, /* Vendor ID of Plextor */
.idProduct = 0xa104, /* Product ID of TV402U */
.bcdDevice_lo = 0x1,
.bcdDevice_hi = 0x1,
.driver_info = (kernel_ulong_t)GO7007_BOARDID_PX_TV402U_ANY,
},
{
.match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
.idVendor = 0x10fd, /* Vendor ID of Anubis Electronics */
.idProduct = 0xde00, /* Product ID of Lifeview LR192 */
.bcdDevice_lo = 0x1,
.bcdDevice_hi = 0x1,
.driver_info = (kernel_ulong_t)GO7007_BOARDID_LIFEVIEW_LR192,
},
{
.match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
.idVendor = 0x1943, /* Vendor ID Sensoray */
.idProduct = 0x2250, /* Product ID of 2250/2251 */
.bcdDevice_lo = 0x1,
.bcdDevice_hi = 0x1,
.driver_info = (kernel_ulong_t)GO7007_BOARDID_SENSORAY_2250,
},
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, go7007_usb_id_table);
/********************* Driver for EZ-USB HPI interface *********************/
static int go7007_usb_vendor_request(struct go7007 *go, int request,
int value, int index, void *transfer_buffer, int length, int in)
{
struct go7007_usb *usb = go->hpi_context;
int timeout = 5000;
if (in) {
return usb_control_msg(usb->usbdev,
usb_rcvctrlpipe(usb->usbdev, 0), request,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
value, index, transfer_buffer, length, timeout);
} else {
return usb_control_msg(usb->usbdev,
usb_sndctrlpipe(usb->usbdev, 0), request,
USB_TYPE_VENDOR | USB_RECIP_DEVICE,
value, index, transfer_buffer, length, timeout);
}
}
static int go7007_usb_interface_reset(struct go7007 *go)
{
struct go7007_usb *usb = go->hpi_context;
u16 intr_val, intr_data;
/* Reset encoder */
if (go7007_write_interrupt(go, 0x0001, 0x0001) < 0)
return -1;
msleep(100);
if (usb->board->flags & GO7007_USB_EZUSB) {
/* Reset buffer in EZ-USB */
#ifdef GO7007_USB_DEBUG
printk(KERN_DEBUG "go7007-usb: resetting EZ-USB buffers\n");
#endif
if (go7007_usb_vendor_request(go, 0x10, 0, 0, NULL, 0, 0) < 0 ||
go7007_usb_vendor_request(go, 0x10, 0, 0, NULL, 0, 0) < 0)
return -1;
/* Reset encoder again */
if (go7007_write_interrupt(go, 0x0001, 0x0001) < 0)
return -1;
msleep(100);
}
/* Wait for an interrupt to indicate successful hardware reset */
if (go7007_read_interrupt(go, &intr_val, &intr_data) < 0 ||
(intr_val & ~0x1) != 0x55aa) {
printk(KERN_ERR
"go7007-usb: unable to reset the USB interface\n");
return -1;
}
return 0;
}
static int go7007_usb_ezusb_write_interrupt(struct go7007 *go,
int addr, int data)
{
struct go7007_usb *usb = go->hpi_context;
int i, r;
u16 status_reg;
int timeout = 500;
#ifdef GO7007_USB_DEBUG
printk(KERN_DEBUG
"go7007-usb: WriteInterrupt: %04x %04x\n", addr, data);
#endif
for (i = 0; i < 100; ++i) {
r = usb_control_msg(usb->usbdev,
usb_rcvctrlpipe(usb->usbdev, 0), 0x14,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
0, HPI_STATUS_ADDR, &status_reg,
sizeof(status_reg), timeout);
if (r < 0)
goto write_int_error;
__le16_to_cpus(&status_reg);
if (!(status_reg & 0x0010))
break;
msleep(10);
}
if (i == 100) {
printk(KERN_ERR
"go7007-usb: device is hung, status reg = 0x%04x\n",
status_reg);
return -1;
}
r = usb_control_msg(usb->usbdev, usb_sndctrlpipe(usb->usbdev, 0), 0x12,
USB_TYPE_VENDOR | USB_RECIP_DEVICE, data,
INT_PARAM_ADDR, NULL, 0, timeout);
if (r < 0)
goto write_int_error;
r = usb_control_msg(usb->usbdev, usb_sndctrlpipe(usb->usbdev, 0),
0x12, USB_TYPE_VENDOR | USB_RECIP_DEVICE, addr,
INT_INDEX_ADDR, NULL, 0, timeout);
if (r < 0)
goto write_int_error;
return 0;
write_int_error:
printk(KERN_ERR "go7007-usb: error in WriteInterrupt: %d\n", r);
return r;
}
static int go7007_usb_onboard_write_interrupt(struct go7007 *go,
int addr, int data)
{
struct go7007_usb *usb = go->hpi_context;
u8 *tbuf;
int r;
int timeout = 500;
#ifdef GO7007_USB_DEBUG
printk(KERN_DEBUG
"go7007-usb: WriteInterrupt: %04x %04x\n", addr, data);
#endif
tbuf = kmalloc(8, GFP_KERNEL);
if (tbuf == NULL)
return -ENOMEM;
memset(tbuf, 0, 8);
tbuf[0] = data & 0xff;
tbuf[1] = data >> 8;
tbuf[2] = addr & 0xff;
tbuf[3] = addr >> 8;
r = usb_control_msg(usb->usbdev, usb_sndctrlpipe(usb->usbdev, 2), 0x00,
USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, 0x55aa,
0xf0f0, tbuf, 8, timeout);
kfree(tbuf);
if (r < 0) {
printk(KERN_ERR "go7007-usb: error in WriteInterrupt: %d\n", r);
return r;
}
return 0;
}
static void go7007_usb_readinterrupt_complete(struct urb *urb)
{
struct go7007 *go = (struct go7007 *)urb->context;
u16 *regs = (u16 *)urb->transfer_buffer;
int status = urb->status;
if (status) {
if (status != -ESHUTDOWN &&
go->status != STATUS_SHUTDOWN) {
printk(KERN_ERR
"go7007-usb: error in read interrupt: %d\n",
urb->status);
} else {
wake_up(&go->interrupt_waitq);
return;
}
} else if (urb->actual_length != urb->transfer_buffer_length) {
printk(KERN_ERR "go7007-usb: short read in interrupt pipe!\n");
} else {
go->interrupt_available = 1;
go->interrupt_data = __le16_to_cpu(regs[0]);
go->interrupt_value = __le16_to_cpu(regs[1]);
#ifdef GO7007_USB_DEBUG
printk(KERN_DEBUG "go7007-usb: ReadInterrupt: %04x %04x\n",
go->interrupt_value, go->interrupt_data);
#endif
}
wake_up(&go->interrupt_waitq);
}
static int go7007_usb_read_interrupt(struct go7007 *go)
{
struct go7007_usb *usb = go->hpi_context;
int r;
r = usb_submit_urb(usb->intr_urb, GFP_KERNEL);
if (r < 0) {
printk(KERN_ERR
"go7007-usb: unable to submit interrupt urb: %d\n", r);
return r;
}
return 0;
}
static void go7007_usb_read_video_pipe_complete(struct urb *urb)
{
struct go7007 *go = (struct go7007 *)urb->context;
int r, status = urb-> status;
if (!go->streaming) {
wake_up_interruptible(&go->frame_waitq);
return;
}
if (status) {
printk(KERN_ERR "go7007-usb: error in video pipe: %d\n", status);
return;
}
if (urb->actual_length != urb->transfer_buffer_length) {
printk(KERN_ERR "go7007-usb: short read in video pipe!\n");
return;
}
go7007_parse_video_stream(go, urb->transfer_buffer, urb->actual_length);
r = usb_submit_urb(urb, GFP_ATOMIC);
if (r < 0)
printk(KERN_ERR "go7007-usb: error in video pipe: %d\n", r);
}
static void go7007_usb_read_audio_pipe_complete(struct urb *urb)
{
struct go7007 *go = (struct go7007 *)urb->context;
int r, status = urb->status;
if (!go->streaming)
return;
if (status) {
printk(KERN_ERR "go7007-usb: error in audio pipe: %d\n", status);
return;
}
if (urb->actual_length != urb->transfer_buffer_length) {
printk(KERN_ERR "go7007-usb: short read in audio pipe!\n");
return;
}
if (go->audio_deliver != NULL)
go->audio_deliver(go, urb->transfer_buffer, urb->actual_length);
r = usb_submit_urb(urb, GFP_ATOMIC);
if (r < 0)
printk(KERN_ERR "go7007-usb: error in audio pipe: %d\n", r);
}
static int go7007_usb_stream_start(struct go7007 *go)
{
struct go7007_usb *usb = go->hpi_context;
int i, r;
for (i = 0; i < 8; ++i) {
r = usb_submit_urb(usb->video_urbs[i], GFP_KERNEL);
if (r < 0) {
printk(KERN_ERR "go7007-usb: error submitting video "
"urb %d: %d\n", i, r);
goto video_submit_failed;
}
}
if (!go->audio_enabled)
return 0;
for (i = 0; i < 8; ++i) {
r = usb_submit_urb(usb->audio_urbs[i], GFP_KERNEL);
if (r < 0) {
printk(KERN_ERR "go7007-usb: error submitting audio "
"urb %d: %d\n", i, r);
goto audio_submit_failed;
}
}
return 0;
audio_submit_failed:
for (i = 0; i < 7; ++i)
usb_kill_urb(usb->audio_urbs[i]);
video_submit_failed:
for (i = 0; i < 8; ++i)
usb_kill_urb(usb->video_urbs[i]);
return -1;
}
static int go7007_usb_stream_stop(struct go7007 *go)
{
struct go7007_usb *usb = go->hpi_context;
int i;
if (go->status == STATUS_SHUTDOWN)
return 0;
for (i = 0; i < 8; ++i)
usb_kill_urb(usb->video_urbs[i]);
if (go->audio_enabled)
for (i = 0; i < 8; ++i)
usb_kill_urb(usb->audio_urbs[i]);
return 0;
}
static int go7007_usb_send_firmware(struct go7007 *go, u8 *data, int len)
{
struct go7007_usb *usb = go->hpi_context;
int transferred, pipe;
int timeout = 500;
#ifdef GO7007_USB_DEBUG
printk(KERN_DEBUG "go7007-usb: DownloadBuffer sending %d bytes\n", len);
#endif
if (usb->board->flags & GO7007_USB_EZUSB)
pipe = usb_sndbulkpipe(usb->usbdev, 2);
else
pipe = usb_sndbulkpipe(usb->usbdev, 3);
return usb_bulk_msg(usb->usbdev, pipe, data, len,
&transferred, timeout);
}
static struct go7007_hpi_ops go7007_usb_ezusb_hpi_ops = {
.interface_reset = go7007_usb_interface_reset,
.write_interrupt = go7007_usb_ezusb_write_interrupt,
.read_interrupt = go7007_usb_read_interrupt,
.stream_start = go7007_usb_stream_start,
.stream_stop = go7007_usb_stream_stop,
.send_firmware = go7007_usb_send_firmware,
};
static struct go7007_hpi_ops go7007_usb_onboard_hpi_ops = {
.interface_reset = go7007_usb_interface_reset,
.write_interrupt = go7007_usb_onboard_write_interrupt,
.read_interrupt = go7007_usb_read_interrupt,
.stream_start = go7007_usb_stream_start,
.stream_stop = go7007_usb_stream_stop,
.send_firmware = go7007_usb_send_firmware,
};
/********************* Driver for EZ-USB I2C adapter *********************/
static int go7007_usb_i2c_master_xfer(struct i2c_adapter *adapter,
struct i2c_msg msgs[], int num)
{
struct go7007 *go = i2c_get_adapdata(adapter);
struct go7007_usb *usb = go->hpi_context;
u8 buf[16];
int buf_len, i;
int ret = -1;
if (go->status == STATUS_SHUTDOWN)
return -1;
down(&usb->i2c_lock);
for (i = 0; i < num; ++i) {
/* The hardware command is "write some bytes then read some
* bytes", so we try to coalesce a write followed by a read
* into a single USB transaction */
if (i + 1 < num && msgs[i].addr == msgs[i + 1].addr &&
!(msgs[i].flags & I2C_M_RD) &&
(msgs[i + 1].flags & I2C_M_RD)) {
#ifdef GO7007_I2C_DEBUG
printk(KERN_DEBUG "go7007-usb: i2c write/read %d/%d "
"bytes on %02x\n", msgs[i].len,
msgs[i + 1].len, msgs[i].addr);
#endif
buf[0] = 0x01;
buf[1] = msgs[i].len + 1;
buf[2] = msgs[i].addr << 1;
memcpy(&buf[3], msgs[i].buf, msgs[i].len);
buf_len = msgs[i].len + 3;
buf[buf_len++] = msgs[++i].len;
} else if (msgs[i].flags & I2C_M_RD) {
#ifdef GO7007_I2C_DEBUG
printk(KERN_DEBUG "go7007-usb: i2c read %d "
"bytes on %02x\n", msgs[i].len,
msgs[i].addr);
#endif
buf[0] = 0x01;
buf[1] = 1;
buf[2] = msgs[i].addr << 1;
buf[3] = msgs[i].len;
buf_len = 4;
} else {
#ifdef GO7007_I2C_DEBUG
printk(KERN_DEBUG "go7007-usb: i2c write %d "
"bytes on %02x\n", msgs[i].len,
msgs[i].addr);
#endif
buf[0] = 0x00;
buf[1] = msgs[i].len + 1;
buf[2] = msgs[i].addr << 1;
memcpy(&buf[3], msgs[i].buf, msgs[i].len);
buf_len = msgs[i].len + 3;
buf[buf_len++] = 0;
}
if (go7007_usb_vendor_request(go, 0x24, 0, 0,
buf, buf_len, 0) < 0)
goto i2c_done;
if (msgs[i].flags & I2C_M_RD) {
memset(buf, 0, sizeof(buf));
if (go7007_usb_vendor_request(go, 0x25, 0, 0, buf,
msgs[i].len + 1, 1) < 0)
goto i2c_done;
memcpy(msgs[i].buf, buf + 1, msgs[i].len);
}
}
ret = 0;
i2c_done:
up(&usb->i2c_lock);
return ret;
}
static u32 go7007_usb_functionality(struct i2c_adapter *adapter)
{
/* No errors are reported by the hardware, so we don't bother
* supporting quick writes to avoid confusing probing */
return (I2C_FUNC_SMBUS_EMUL) & ~I2C_FUNC_SMBUS_QUICK;
}
static struct i2c_algorithm go7007_usb_algo = {
.master_xfer = go7007_usb_i2c_master_xfer,
.functionality = go7007_usb_functionality,
};
static struct i2c_adapter go7007_usb_adap_templ = {
.owner = THIS_MODULE,
.name = "WIS GO7007SB EZ-USB",
.algo = &go7007_usb_algo,
};
/********************* USB add/remove functions *********************/
static int go7007_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct go7007 *go;
struct go7007_usb *usb;
struct go7007_usb_board *board;
struct usb_device *usbdev = interface_to_usbdev(intf);
char *name;
int video_pipe, i, v_urb_len;
printk(KERN_DEBUG "go7007-usb: probing new GO7007 USB board\n");
switch (id->driver_info) {
case GO7007_BOARDID_MATRIX_II:
name = "WIS Matrix II or compatible";
board = &board_matrix_ii;
break;
case GO7007_BOARDID_MATRIX_RELOAD:
name = "WIS Matrix Reloaded or compatible";
board = &board_matrix_reload;
break;
case GO7007_BOARDID_MATRIX_REV:
name = "WIS Matrix Revolution or compatible";
board = &board_matrix_revolution;
break;
case GO7007_BOARDID_STAR_TREK:
name = "WIS Star Trek or compatible";
board = &board_star_trek;
break;
case GO7007_BOARDID_XMEN:
name = "WIS XMen or compatible";
board = &board_xmen;
break;
case GO7007_BOARDID_XMEN_II:
name = "WIS XMen II or compatible";
board = &board_xmen;
break;
case GO7007_BOARDID_XMEN_III:
name = "WIS XMen III or compatible";
board = &board_xmen;
break;
case GO7007_BOARDID_PX_M402U:
name = "Plextor PX-M402U";
board = &board_matrix_ii;
break;
case GO7007_BOARDID_PX_TV402U_ANY:
name = "Plextor PX-TV402U (unknown tuner)";
board = &board_px_tv402u;
break;
case GO7007_BOARDID_LIFEVIEW_LR192:
printk(KERN_ERR "go7007-usb: The Lifeview TV Walker Ultra "
"is not supported. Sorry!\n");
return 0;
name = "Lifeview TV Walker Ultra";
board = &board_lifeview_lr192;
break;
case GO7007_BOARDID_SENSORAY_2250:
printk(KERN_INFO "Sensoray 2250 found\n");
name = "Sensoray 2250/2251\n";
board = &board_sensoray_2250;
break;
default:
printk(KERN_ERR "go7007-usb: unknown board ID %d!\n",
(unsigned int)id->driver_info);
return 0;
}
usb = kzalloc(sizeof(struct go7007_usb), GFP_KERNEL);
if (usb == NULL)
return -ENOMEM;
/* Allocate the URB and buffer for receiving incoming interrupts */
usb->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
if (usb->intr_urb == NULL)
goto allocfail;
usb->intr_urb->transfer_buffer = kmalloc(2*sizeof(u16), GFP_KERNEL);
if (usb->intr_urb->transfer_buffer == NULL)
goto allocfail;
go = go7007_alloc(&board->main_info, &intf->dev);
if (go == NULL)
goto allocfail;
usb->board = board;
usb->usbdev = usbdev;
go->board_id = id->driver_info;
strncpy(go->name, name, sizeof(go->name));
if (board->flags & GO7007_USB_EZUSB)
go->hpi_ops = &go7007_usb_ezusb_hpi_ops;
else
go->hpi_ops = &go7007_usb_onboard_hpi_ops;
go->hpi_context = usb;
usb_fill_int_urb(usb->intr_urb, usb->usbdev,
usb_rcvintpipe(usb->usbdev, 4),
usb->intr_urb->transfer_buffer, 2*sizeof(u16),
go7007_usb_readinterrupt_complete, go, 8);
usb_set_intfdata(intf, go);
/* Boot the GO7007 */
if (go7007_boot_encoder(go, go->board_info->flags &
GO7007_BOARD_USE_ONBOARD_I2C) < 0)
goto initfail;
/* Register the EZ-USB I2C adapter, if we're using it */
if (board->flags & GO7007_USB_EZUSB_I2C) {
memcpy(&go->i2c_adapter, &go7007_usb_adap_templ,
sizeof(go7007_usb_adap_templ));
init_MUTEX(&usb->i2c_lock);
go->i2c_adapter.dev.parent = go->dev;
i2c_set_adapdata(&go->i2c_adapter, go);
if (i2c_add_adapter(&go->i2c_adapter) < 0) {
printk(KERN_ERR
"go7007-usb: error: i2c_add_adapter failed\n");
goto initfail;
}
go->i2c_adapter_online = 1;
}
/* Pelco and Adlink reused the XMen and XMen-III vendor and product
* IDs for their own incompatible designs. We can detect XMen boards
* by probing the sensor, but there is no way to probe the sensors on
* the Pelco and Adlink designs so we default to the Adlink. If it
* is actually a Pelco, the user must set the assume_endura module
* parameter. */
if ((go->board_id == GO7007_BOARDID_XMEN ||
go->board_id == GO7007_BOARDID_XMEN_III) &&
go->i2c_adapter_online) {
union i2c_smbus_data data;
/* Check to see if register 0x0A is 0x76 */
i2c_smbus_xfer(&go->i2c_adapter, 0x21, I2C_CLIENT_SCCB,
I2C_SMBUS_READ, 0x0A, I2C_SMBUS_BYTE_DATA, &data);
if (data.byte != 0x76) {
if (assume_endura) {
go->board_id = GO7007_BOARDID_ENDURA;
usb->board = board = &board_endura;
go->board_info = &board->main_info;
strncpy(go->name, "Pelco Endura",
sizeof(go->name));
} else {
u16 channel;
/* set GPIO5 to be an output, currently low */
go7007_write_addr(go, 0x3c82, 0x0000);
go7007_write_addr(go, 0x3c80, 0x00df);
/* read channel number from GPIO[1:0] */
go7007_read_addr(go, 0x3c81, &channel);
channel &= 0x3;
go->board_id = GO7007_BOARDID_ADLINK_MPG24;
usb->board = board = &board_adlink_mpg24;
go->board_info = &board->main_info;
go->channel_number = channel;
snprintf(go->name, sizeof(go->name),
"Adlink PCI-MPG24, channel #%d",
channel);
}
}
}
/* Probe the tuner model on the TV402U */
if (go->board_id == GO7007_BOARDID_PX_TV402U_ANY) {
u8 data[3];
/* Board strapping indicates tuner model */
if (go7007_usb_vendor_request(go, 0x41, 0, 0, data, 3, 1) < 0) {
printk(KERN_ERR "go7007-usb: GPIO read failed!\n");
goto initfail;
}
switch (data[0] >> 6) {
case 1:
go->board_id = GO7007_BOARDID_PX_TV402U_EU;
go->tuner_type = TUNER_SONY_BTF_PG472Z;
strncpy(go->name, "Plextor PX-TV402U-EU",
sizeof(go->name));
break;
case 2:
go->board_id = GO7007_BOARDID_PX_TV402U_JP;
go->tuner_type = TUNER_SONY_BTF_PK467Z;
strncpy(go->name, "Plextor PX-TV402U-JP",
sizeof(go->name));
break;
case 3:
go->board_id = GO7007_BOARDID_PX_TV402U_NA;
go->tuner_type = TUNER_SONY_BTF_PB463Z;
strncpy(go->name, "Plextor PX-TV402U-NA",
sizeof(go->name));
break;
default:
printk(KERN_DEBUG "go7007-usb: unable to detect "
"tuner type!\n");
break;
}
/* Configure tuner mode selection inputs connected
* to the EZ-USB GPIO output pins */
if (go7007_usb_vendor_request(go, 0x40, 0x7f02, 0,
NULL, 0, 0) < 0) {
printk(KERN_ERR
"go7007-usb: GPIO write failed!\n");
goto initfail;
}
}
/* Print a nasty message if the user attempts to use a USB2.0 device in
* a USB1.1 port. There will be silent corruption of the stream. */
if ((board->flags & GO7007_USB_EZUSB) &&
usbdev->speed != USB_SPEED_HIGH)
printk(KERN_ERR "go7007-usb: *** WARNING *** This device "
"must be connected to a USB 2.0 port! "
"Attempting to capture video through a USB 1.1 "
"port will result in stream corruption, even "
"at low bitrates!\n");
/* Do any final GO7007 initialization, then register the
* V4L2 and ALSA interfaces */
if (go7007_register_encoder(go) < 0)
goto initfail;
/* Allocate the URBs and buffers for receiving the video stream */
if (board->flags & GO7007_USB_EZUSB) {
v_urb_len = 1024;
video_pipe = usb_rcvbulkpipe(usb->usbdev, 6);
} else {
v_urb_len = 512;
video_pipe = usb_rcvbulkpipe(usb->usbdev, 1);
}
for (i = 0; i < 8; ++i) {
usb->video_urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
if (usb->video_urbs[i] == NULL)
goto initfail;
usb->video_urbs[i]->transfer_buffer =
kmalloc(v_urb_len, GFP_KERNEL);
if (usb->video_urbs[i]->transfer_buffer == NULL)
goto initfail;
usb_fill_bulk_urb(usb->video_urbs[i], usb->usbdev, video_pipe,
usb->video_urbs[i]->transfer_buffer, v_urb_len,
go7007_usb_read_video_pipe_complete, go);
}
/* Allocate the URBs and buffers for receiving the audio stream */
if ((board->flags & GO7007_USB_EZUSB) && go->audio_enabled)
for (i = 0; i < 8; ++i) {
usb->audio_urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
if (usb->audio_urbs[i] == NULL)
goto initfail;
usb->audio_urbs[i]->transfer_buffer = kmalloc(4096,
GFP_KERNEL);
if (usb->audio_urbs[i]->transfer_buffer == NULL)
goto initfail;
usb_fill_bulk_urb(usb->audio_urbs[i], usb->usbdev,
usb_rcvbulkpipe(usb->usbdev, 8),
usb->audio_urbs[i]->transfer_buffer, 4096,
go7007_usb_read_audio_pipe_complete, go);
}
go->status = STATUS_ONLINE;
return 0;
initfail:
go->status = STATUS_SHUTDOWN;
return 0;
allocfail:
if (usb->intr_urb) {
kfree(usb->intr_urb->transfer_buffer);
usb_free_urb(usb->intr_urb);
}
kfree(usb);
return -ENOMEM;
}
static void go7007_usb_disconnect(struct usb_interface *intf)
{
struct go7007 *go = usb_get_intfdata(intf);
struct go7007_usb *usb = go->hpi_context;
struct urb *vurb, *aurb;
int i;
go->status = STATUS_SHUTDOWN;
usb_kill_urb(usb->intr_urb);
/* Free USB-related structs */
for (i = 0; i < 8; ++i) {
vurb = usb->video_urbs[i];
if (vurb) {
usb_kill_urb(vurb);
if (vurb->transfer_buffer)
kfree(vurb->transfer_buffer);
usb_free_urb(vurb);
}
aurb = usb->audio_urbs[i];
if (aurb) {
usb_kill_urb(aurb);
if (aurb->transfer_buffer)
kfree(aurb->transfer_buffer);
usb_free_urb(aurb);
}
}
kfree(usb->intr_urb->transfer_buffer);
usb_free_urb(usb->intr_urb);
kfree(go->hpi_context);
go7007_remove(go);
}
static struct usb_driver go7007_usb_driver = {
.name = "go7007",
.probe = go7007_usb_probe,
.disconnect = go7007_usb_disconnect,
.id_table = go7007_usb_id_table,
};
static int __init go7007_usb_init(void)
{
return usb_register(&go7007_usb_driver);
}
static void __exit go7007_usb_cleanup(void)
{
usb_deregister(&go7007_usb_driver);
}
module_init(go7007_usb_init);
module_exit(go7007_usb_cleanup);
MODULE_LICENSE("GPL v2");