summaryrefslogtreecommitdiff
path: root/v4l_experimental/pvrusb2/pvrusb2-hdw.c
diff options
context:
space:
mode:
Diffstat (limited to 'v4l_experimental/pvrusb2/pvrusb2-hdw.c')
-rw-r--r--v4l_experimental/pvrusb2/pvrusb2-hdw.c2338
1 files changed, 0 insertions, 2338 deletions
diff --git a/v4l_experimental/pvrusb2/pvrusb2-hdw.c b/v4l_experimental/pvrusb2/pvrusb2-hdw.c
deleted file mode 100644
index 20206cff9..000000000
--- a/v4l_experimental/pvrusb2/pvrusb2-hdw.c
+++ /dev/null
@@ -1,2338 +0,0 @@
-/*
- *
- * $Id: pvrusb2-hdw.c,v 1.13 2006/01/23 06:58:06 mcisely Exp $
- *
- * Copyright (C) 2005 Mike Isely <isely@pobox.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * 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 "compat.h"
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/firmware.h>
-#include <asm/semaphore.h>
-#include "pvrusb2.h"
-#include "pvrusb2-util.h"
-#include "pvrusb2-hdw.h"
-#include "pvrusb2-i2c-core.h"
-#include "pvrusb2-tuner.h"
-#include "pvrusb2-eeprom.h"
-#include "pvrusb2-hdw-internal.h"
-#include "pvrusb2-encoder.h"
-#include "pvrusb2-debug.h"
-
-static struct pvr2_hdw *unit_pointers[PVR_NUM] = {[ 0 ... PVR_NUM-1 ] = 0};
-DECLARE_MUTEX(pvr2_unit_sem);
-
-static int ctlchg = 0;
-static int initusbreset = 1;
-static int procreload = 0;
-static int tuner[PVR_NUM] = { [0 ... PVR_NUM-1] = -1 };
-static int tolerance[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 };
-
-module_param(ctlchg, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(ctlchg, "0=optimize ctl change 1=always accept new ctl value");
-module_param(initusbreset, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(initusbreset, "Do USB reset device on probe");
-module_param(procreload, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(procreload,
- "Attempt init failure recovery with firmware reload");
-module_param_array(tuner, int, NULL, 0444);
-MODULE_PARM_DESC(tuner,"specify installed tuner type");
-module_param_array(tolerance, int, NULL, 0444);
-MODULE_PARM_DESC(tolerance,"specify stream error tolerance");
-
-#define PVR2_CTL_WRITE_ENDPOINT 0x01
-#define PVR2_CTL_READ_ENDPOINT 0x81
-
-#define PVR2_GPIO_IN 0x9008
-#define PVR2_GPIO_OUT 0x900c
-#define PVR2_GPIO_DIR 0x9020
-
-#define trace_firmware(...) pvr2_trace(PVR2_TRACE_FIRMWARE,__VA_ARGS__)
-
-#define PVR2_FIRMWARE_ENDPOINT 0x02
-
-/* size of a firmware chunk */
-#define FIRMWARE_CHUNK_SIZE 0x2000
-
-/* Various files we will load with firmware_entry */
-#define FIRMWARE1_FILE "pvrusb2.f1"
-#define FIRMWARE2_FILE "pvrusb2.f2"
-
-typedef int (*pvr2_ctl_set_func)(struct pvr2_hdw *,int ctl_id,int val);
-typedef int (*pvr2_ctl_get_func)(struct pvr2_hdw *,int ctl_id);
-
-struct pvr2_ctl_def {
- const char *name;
- pvr2_ctl_set_func set_func;
- pvr2_ctl_get_func get_func;
- int max_value;
- int min_value;
- int skip_init;
- int default_value;
- const char **value_defs_ptr;
- unsigned int value_defs_count;
-};
-
-
-static const char *control_values_srate[] = {
- [PVR2_CVAL_SRATE_48] = "48KHz",
- [PVR2_CVAL_SRATE_44_1] = "44.1KHz",
-};
-
-
-static const char *control_values_audiobitrate[] = {
- [PVR2_CVAL_AUDIOBITRATE_384] = "384kb/s",
- [PVR2_CVAL_AUDIOBITRATE_320] = "320kb/s",
- [PVR2_CVAL_AUDIOBITRATE_256] = "256kb/s",
- [PVR2_CVAL_AUDIOBITRATE_224] = "224kb/s",
- [PVR2_CVAL_AUDIOBITRATE_192] = "192kb/s",
- [PVR2_CVAL_AUDIOBITRATE_160] = "160kb/s",
- [PVR2_CVAL_AUDIOBITRATE_128] = "128kb/s",
- [PVR2_CVAL_AUDIOBITRATE_112] = "112kb/s",
- [PVR2_CVAL_AUDIOBITRATE_96] = "96kb/s",
- [PVR2_CVAL_AUDIOBITRATE_80] = "80kb/s",
- [PVR2_CVAL_AUDIOBITRATE_64] = "64kb/s",
- [PVR2_CVAL_AUDIOBITRATE_56] = "56kb/s",
- [PVR2_CVAL_AUDIOBITRATE_48] = "48kb/s",
- [PVR2_CVAL_AUDIOBITRATE_32] = "32kb/s",
- [PVR2_CVAL_AUDIOBITRATE_VBR] = "VBR",
-};
-
-
-static const char *control_values_audioemphasis[] = {
- [PVR2_CVAL_AUDIOEMPHASIS_NONE] = "None",
- [PVR2_CVAL_AUDIOEMPHASIS_50_15] = "50/15us",
- [PVR2_CVAL_AUDIOEMPHASIS_CCITT] = "CCITT J.17",
-};
-
-
-static const char *control_values_videostandard[] = {
- [PVR2_CVAL_VIDEOSTANDARD_NTSC_M] = "NTSC-M",
- [PVR2_CVAL_VIDEOSTANDARD_SECAM_L] = "SECAM-L",
- [PVR2_CVAL_VIDEOSTANDARD_PAL_BG] = "PAL-BG",
- [PVR2_CVAL_VIDEOSTANDARD_PAL_I] = "PAL-I",
- [PVR2_CVAL_VIDEOSTANDARD_PAL_DK] = "PAL-DK",
- [PVR2_CVAL_VIDEOSTANDARD_PAL_M] = "PAL-M",
-};
-
-
-static const char *control_values_input[] = {
- [PVR2_CVAL_INPUT_TV] = "television", /*xawtv needs this name*/
- [PVR2_CVAL_INPUT_RADIO] = "radio",
- [PVR2_CVAL_INPUT_SVIDEO] = "s-video",
- [PVR2_CVAL_INPUT_COMPOSITE] = "composite",
-};
-
-
-static const char *control_values_audiomode[] = {
- [PVR2_CVAL_AUDIOMODE_MONO] = "Mono",
- [PVR2_CVAL_AUDIOMODE_STEREO] = "Stereo",
- [PVR2_CVAL_AUDIOMODE_SAP] = "SAP",
- [PVR2_CVAL_AUDIOMODE_LANG1] = "Lang1",
- [PVR2_CVAL_AUDIOMODE_LANG2] = "Lang2",
-};
-
-
-static const char *control_values_hsm[] = {
- [PVR2_CVAL_HSM_FAIL] = "Fail",
- [PVR2_CVAL_HSM_HIGH] = "High",
- [PVR2_CVAL_HSM_FULL] = "Full",
-};
-
-
-#define VDEF(x) \
- .value_defs_ptr = x, \
- .value_defs_count = (sizeof(x)/sizeof(x[0]))
-
-static int pvr2_ctl_set_chanprog_id(struct pvr2_hdw *hdw,int ctl_id,int value);
-static int pvr2_ctl_get_chanprog_id(struct pvr2_hdw *hdw,int ctl_id);
-static int pvr2_ctl_get_signal(struct pvr2_hdw *hdw,int ctl_id);
-static int pvr2_ctl_get_streaming(struct pvr2_hdw *hdw,int ctl_id);
-static int pvr2_ctl_get_hsm(struct pvr2_hdw *hdw,int ctl_id);
-static int pvr2_ctl_get_subsys_mask(struct pvr2_hdw *hdw,int ctl_id);
-static int pvr2_ctl_set_subsys_mask(struct pvr2_hdw *hdw,int ctl_id,int val);
-static int pvr2_ctl_get_subsys_stream_mask(struct pvr2_hdw *hdw,int ctl_id);
-static int pvr2_ctl_set_subsys_stream_mask(struct pvr2_hdw *hdw,int ctl_id,
- int val);
-
-static struct pvr2_ctl_def control_defs[PVR2_CID_COUNT] =
-{
- [PVR2_CID_BRIGHTNESS] = {
- .name = "Brightness",
- .min_value = 0,
- .max_value = 255,
- .default_value = 128,
- },
- [PVR2_CID_CONTRAST] = {
- .name = "Contrast",
- .min_value = 0,
- .max_value = 127,
- .default_value = 68,
- },
- [PVR2_CID_SATURATION] = {
- .name = "Saturation",
- .min_value = 0,
- .max_value = 127,
- .default_value = 64,
- },
- [PVR2_CID_HUE] = {
- .name = "Hue",
- .min_value = -128,
- .max_value = 127,
- .default_value = 0,
- },
- [PVR2_CID_VOLUME] = {
- .name = "Volume",
- .min_value = 0,
- .max_value = 65535,
- .default_value = 65535,
- },
- [PVR2_CID_BALANCE] = {
- .name = "Balance",
- .min_value = -32768,
- .max_value = 32767,
- .default_value = 0,
- },
- [PVR2_CID_BASS] = {
- .name = "Bass",
- .min_value = -32768,
- .max_value = 32767,
- .default_value = 0,
- },
- [PVR2_CID_TREBLE] = {
- .name = "Treble",
- .min_value = -32768,
- .max_value = 32767,
- .default_value = 0,
- },
- [PVR2_CID_MUTE] = {
- .name = "Mute",
- .min_value = 0,
- .max_value = 1,
- .default_value = 0,
- },
- [PVR2_CID_SRATE] = {
- .name = "Sample rate",
- .min_value = PVR2_CVAL_SRATE_MIN,
- .max_value = PVR2_CVAL_SRATE_MAX,
- .default_value = PVR2_CVAL_SRATE_48,
- VDEF(control_values_srate),
- },
- [PVR2_CID_AUDIOBITRATE] = {
- .name = "Audio Bitrate",
- .min_value = PVR2_CVAL_AUDIOBITRATE_MIN,
- .max_value = PVR2_CVAL_AUDIOBITRATE_MAX,
- .default_value = PVR2_CVAL_AUDIOBITRATE_224,
- VDEF(control_values_audiobitrate),
- },
- [PVR2_CID_AUDIOCRC] = {
- .name = "Audio CRC",
- .min_value = 0,
- .max_value = 1,
- .default_value = 1,
- },
- [PVR2_CID_AUDIOEMPHASIS] = {
- .name = "Audio Emphasis",
- .min_value = PVR2_CVAL_AUDIOEMPHASIS_MIN,
- .max_value = PVR2_CVAL_AUDIOEMPHASIS_MAX,
- .default_value = PVR2_CVAL_AUDIOEMPHASIS_NONE,
- VDEF(control_values_audioemphasis),
- },
- [PVR2_CID_VBR] = {
- .name = "Variable video bitrate",
- .min_value = 0,
- .max_value = 1,
- .default_value = 0,
- },
- [PVR2_CID_AVERAGEVIDEOBITRATE] = {
- .name = "Average video bitrate",
- .min_value = 1,
- .max_value = 20000000,
- .default_value = 6000000,
- },
- [PVR2_CID_PEAKVIDEOBITRATE] = {
- .name = "Peak video bitrate",
- .min_value = 1,
- .max_value = 20000000,
- .default_value = 6000000,
- },
- [PVR2_CID_VIDEOSTANDARD] = {
- .name = "Video Standard",
- .min_value = PVR2_CVAL_VIDEOSTANDARD_MIN,
- .max_value = PVR2_CVAL_VIDEOSTANDARD_MAX,
- .default_value = PVR2_CVAL_VIDEOSTANDARD_NTSC_M,
- VDEF(control_values_videostandard),
- },
- [PVR2_CID_INPUT] = {
- .name = "Video Source",
- .min_value = PVR2_CVAL_INPUT_MIN,
- .max_value = PVR2_CVAL_INPUT_MAX,
- .default_value = PVR2_CVAL_INPUT_TV,
- VDEF(control_values_input),
- },
- [PVR2_CID_AUDIOMODE] = {
- .name = "Audio Mode",
- .min_value = PVR2_CVAL_AUDIOMODE_MIN,
- .max_value = PVR2_CVAL_AUDIOMODE_MAX,
- .default_value = PVR2_CVAL_AUDIOMODE_STEREO,
- VDEF(control_values_audiomode),
- },
- [PVR2_CID_FREQUENCY] = {
- .name = "Tuner Frequency (Hz)",
- .min_value = 55250000L,
- .max_value = 801250000L,
- .default_value = 175250000L,
- },
- [PVR2_CID_HRES] = {
- .name = "Horizontal capture resolution",
- .min_value = 320,
- .max_value = 720,
- .default_value = 720,
- },
- [PVR2_CID_VRES] = {
- .name = "Vertical capture resolution",
- .min_value = 200,
- .max_value = 625,
- .default_value = 480,
- },
- [PVR2_CID_INTERLACE] = {
- .name = "Interlace mode",
- .min_value = 0,
- .max_value = 1,
- .default_value = 0,
- },
- [PVR2_CID_AUDIOLAYER] = {
- .name = "Audio Layer",
- .min_value = 0, /* This is all a wild guess */
- .max_value = 3,
- .default_value = 2, /* Appears to be all that is supported */
- },
- [PVR2_CID_CHANNEL] = {
- .name = "Channel",
- .min_value = 0,
- .max_value = FREQTABLE_SIZE,
- .default_value = 0,
- },
- [PVR2_CID_CHANPROG_ID] = {
- .name = "Channel Program ID",
- .min_value = 0,
- .max_value = FREQTABLE_SIZE,
- .default_value = 0,
- },
- [PVR2_CID_CHANPROG_FREQ] = {
- .name = "Channel Program Frequency",
- .min_value = 55250000L,
- .max_value = 801250000L,
- .skip_init = !0,
- .set_func = pvr2_ctl_set_chanprog_id,
- .get_func = pvr2_ctl_get_chanprog_id,
- },
- [PVR2_CID_SIGNAL_PRESENT] = {
- .name = "Signal Present",
- .min_value = 0,
- .max_value = 1,
- .get_func = pvr2_ctl_get_signal,
- },
- [PVR2_CID_STREAMING_ENABLED] = {
- .name = "Streaming Enabled",
- .min_value = 0,
- .max_value = 1,
- .get_func = pvr2_ctl_get_streaming,
- },
- [PVR2_CID_HSM] = {
- .name = "USB Speed",
- .min_value = PVR2_CVAL_HSM_MIN,
- .max_value = PVR2_CVAL_HSM_MAX,
- .get_func = pvr2_ctl_get_hsm,
- VDEF(control_values_hsm),
- },
- [PVR2_CID_SUBSYS_MASK] = {
- .name = "Subsystem enabled mask",
- .min_value = 0,
- .max_value = 0x7fffffff,
- .skip_init = !0,
- .get_func = pvr2_ctl_get_subsys_mask,
- .set_func = pvr2_ctl_set_subsys_mask,
- },
- [PVR2_CID_SUBSYS_STREAM_MASK] = {
- .name = "Subsystem stream mask",
- .min_value = 0,
- .max_value = 0x7fffffff,
- .skip_init = !0,
- .get_func = pvr2_ctl_get_subsys_stream_mask,
- .set_func = pvr2_ctl_set_subsys_stream_mask,
- },
-};
-
-#undef VDEF
-
-
-const char *pvr2_config_get_name(enum pvr2_config cfg)
-{
- switch (cfg) {
- case pvr2_config_empty: return "empty";
- case pvr2_config_mpeg: return "mpeg";
- case pvr2_config_vbi: return "vbi";
- case pvr2_config_radio: return "radio";
- }
- return "<unknown>";
-}
-
-
-struct usb_device *pvr2_hdw_get_dev(struct pvr2_hdw *hdw)
-{
- return hdw->usb_dev;
-}
-
-
-unsigned long pvr2_hdw_get_sn(struct pvr2_hdw *hdw)
-{
- return hdw->serial_number;
-}
-
-
-struct pvr2_hdw *pvr2_hdw_find(int unit_number)
-{
- if (unit_number < 0) return 0;
- if (unit_number >= PVR_NUM) return 0;
- return unit_pointers[unit_number];
-}
-
-
-int pvr2_hdw_get_unit_number(struct pvr2_hdw *hdw)
-{
- return hdw->unit_number;
-}
-
-
-/*
- * pvr2_upload_firmware1().
- *
- * Send the 8051 firmware to the device. After the upload, arrange for
- * device to re-enumerate.
- *
- * NOTE : the pointer to the firmware data given by request_firmware()
- * is not suitable for an usb transaction.
- *
- */
-int pvr2_upload_firmware1(struct pvr2_hdw *hdw)
-{
- const struct firmware *fw_entry = 0;
- void *fw_ptr;
- unsigned int pipe;
- int ret;
- u16 address;
- const char *firmware_file = FIRMWARE1_FILE;
-
- hdw->fw1_state = FW1_STATE_FAILED; // default result
-
- trace_firmware("pvr2_upload_firmware1");
-
- usb_settoggle(hdw->usb_dev, 0 & 0xf, !(0 & USB_DIR_IN), 0);
- usb_clear_halt(hdw->usb_dev, usb_sndbulkpipe(hdw->usb_dev, 0 & 0x7f));
-
- pipe = usb_sndctrlpipe(hdw->usb_dev, 0);
- ret = request_firmware(&fw_entry, firmware_file, &hdw->usb_dev->dev);
-
- if (ret) {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "request_firmware failed for '%s' code=%d",
- firmware_file,ret);
- if (ret == -ENOENT) {
- hdw->fw1_state = FW1_STATE_MISSING;
- }
- return ret;
- }
-
- if (fw_entry->size != 0x2000){
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,"wrong fx2 firmware size");
- release_firmware(fw_entry);
- return -ENOMEM;
- }
-
- fw_ptr = kmalloc(0x800, GFP_KERNEL);
- if (fw_ptr == NULL){
- release_firmware(fw_entry);
- return -ENOMEM;
- }
-
- /* We have to hold the CPU during firmware upload. */
- pvr2_hdw_cpureset_assert(hdw,1);
-
- /* upload the firmware to address 0000-1fff in 2048 (=0x800) bytes
- chunk. */
-
- ret = 0;
- for(address = 0; address < fw_entry->size; address += 0x800) {
- memcpy(fw_ptr, fw_entry->data + address, 0x800);
- ret += usb_control_msg(hdw->usb_dev, pipe, 0xa0, 0x40, address,
- 0, fw_ptr, 0x800, HZ);
- }
-
- trace_firmware("Upload done, releasing device's CPU");
-
- /* Now release the CPU. It will disconnect and reconnect later. */
- pvr2_hdw_cpureset_assert(hdw,0);
-
- kfree(fw_ptr);
- release_firmware(fw_entry);
-
- trace_firmware("Upload done (%d bytes sent)",ret);
-
- /* We should have written 8192 bytes */
- if (ret == 8192) {
- hdw->fw1_state = FW1_STATE_RELOAD;
- return 0;
- }
-
- return -EIO;
-}
-
-
-/*
- * pvr2_upload_firmware2()
- *
- * This uploads encoder firmware on endpoint 2.
- *
- */
-
-int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
-{
- const struct firmware *fw_entry = 0;
- void *fw_ptr;
- unsigned int pipe, fw_len, fw_done;
- int actual_length;
- int ret = 0;
-
- trace_firmware("pvr2_upload_firmware2");
-
- /* First prepare firmware loading */
- ret |= pvr2_hdw_cmd_soft_reset(hdw);
- ret |= pvr2_write_register(hdw, 0x0048, 0xffffffff); /*interrupt mask*/
- ret |= pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000088); /*gpio dir*/
- ret |= pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000008); /*gpio output state*/
- ret |= pvr2_hdw_cmd_deep_reset(hdw);
- ret |= pvr2_write_register(hdw, 0xa064, 0x00000000); /*APU command*/
- ret |= pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000408); /*gpio dir*/
- ret |= pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000008); /*gpio output state*/
- ret |= pvr2_write_register(hdw, 0x9058, 0xffffffed); /*VPU ctrl*/
- ret |= pvr2_write_register(hdw, 0x9054, 0xfffffffd); /*reset hw blocks*/
- ret |= pvr2_write_register(hdw, 0x07f8, 0x80000800); /*encoder SDRAM refresh*/
- ret |= pvr2_write_register(hdw, 0x07fc, 0x0000001a); /*encoder SDRAM pre-charge*/
- ret |= pvr2_write_register(hdw, 0x0700, 0x00000000); /*I2C clock*/
- ret |= pvr2_write_register(hdw, 0xaa00, 0x00000000); /*unknown*/
- ret |= pvr2_write_register(hdw, 0xaa04, 0x00057810); /*unknown*/
- ret |= pvr2_write_register(hdw, 0xaa10, 0x00148500); /*unknown*/
- ret |= pvr2_write_register(hdw, 0xaa18, 0x00840000); /*unknown*/
- ret |= pvr2_write_u8(hdw, 0x52, 0);
- ret |= pvr2_write_u16(hdw, 0x0600, 0);
-
- if (ret) {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "firmware2 upload prep failed, ret=%d",ret);
- return ret;
- }
-
- /* Now send firmware */
-
- ret = request_firmware(&fw_entry, FIRMWARE2_FILE, &hdw->usb_dev->dev);
-
- if (ret) {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "request_firmware failed for '%s'", FIRMWARE2_FILE);
- if (ret == -ENOENT) {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "***WARNING***"
- " Device encoder firmware"
- " seems to be missing.");
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "Did you install the pvrusb2 firmware files"
- " in their proper location?");
- }
- return ret;
- }
-
- fw_len = fw_entry->size;
-
- if (fw_len % FIRMWARE_CHUNK_SIZE) {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "size of %s must be a multiple of 8192B",
- FIRMWARE2_FILE);
- release_firmware(fw_entry);
- return -1;
- }
-
- fw_ptr = kmalloc(FIRMWARE_CHUNK_SIZE, GFP_KERNEL);
- if (fw_ptr == NULL){
- release_firmware(fw_entry);
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "failed to allocate memory for firmware2 upload");
- return -ENOMEM;
- }
-
- pipe = usb_sndbulkpipe(hdw->usb_dev, PVR2_FIRMWARE_ENDPOINT);
-
- for (fw_done = 0 ; (fw_done < fw_len) && !ret ;
- fw_done += FIRMWARE_CHUNK_SIZE ) {
- int i;
- memcpy(fw_ptr, fw_entry->data + fw_done, FIRMWARE_CHUNK_SIZE);
- /* Usbsnoop log shows that we must swap bytes... */
- for (i = 0; i < FIRMWARE_CHUNK_SIZE/4 ; i++)
- ((u32 *)fw_ptr)[i] = ___swab32(((u32 *)fw_ptr)[i]);
-
- ret |= usb_bulk_msg(hdw->usb_dev, pipe, fw_ptr,
- FIRMWARE_CHUNK_SIZE,
- &actual_length, HZ);
- ret |= (actual_length != FIRMWARE_CHUNK_SIZE);
- }
-
- trace_firmware("upload of %s : %i / %i ",
- FIRMWARE2_FILE,fw_done,fw_len);
-
- kfree(fw_ptr);
- release_firmware(fw_entry);
-
- if (ret) {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "firmware2 upload transfer failure");
- return ret;
- }
-
- /* Finish upload */
-
- ret |= pvr2_write_register(hdw, 0x9054, 0xffffffff); /*reset hw blocks*/
- ret |= pvr2_write_register(hdw, 0x9058, 0xffffffe8); /*VPU ctrl*/
- ret |= pvr2_write_u16(hdw, 0x0600, 0);
-
- if (ret) {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "firmware2 upload post-proc failure");
- } else {
- hdw->subsys_enabled_mask |= PVR2_SUBSYS_ENC_FIRMWARE;
- }
- return ret;
-}
-
-
-#define FIRMWARE_RECOVERY_BITS \
- (PVR2_SUBSYS_ENC_CFG | \
- PVR2_SUBSYS_ENC_RUN | \
- PVR2_SUBSYS_ENC_FIRMWARE | \
- PVR2_SUBSYS_USBSTREAM_RUN)
-
-/*
-
- This single function is key to pretty much everything. The pvrusb2
- device can logically be viewed as a series of subsystems which can be
- stopped / started or unconfigured / configured. To get things streaming,
- one must configure everything and start everything, but there may be
- various reasons over time to deconfigure something or stop something.
- This function handles all of this activity. Everything EVERYWHERE that
- must affect a subsystem eventually comes here to do the work.
-
- The current state of all subsystems is represented by a single bit mask,
- known as subsys_enabled_mask. The bit positions are defined by the
- PVR2_SUBSYS_xxxx macros, with one subsystem per bit position. At any
- time the set of configured or active subsystems can be queried just by
- looking at that mask. To change bits in that mask, this function here
- must be called. The "msk" argument indicates which bit positions to
- change, and the "val" argument defines the new values for the positions
- defined by "msk".
-
- There is a priority ordering of starting / stopping things, and for
- multiple requested changes, this function implements that ordering.
- (Thus we will act on a request to load encoder firmware before we
- configure the encoder.) In addition to priority ordering, there is a
- recovery strategy implemented here. If a particular step fails and we
- detect that failure, this function will clear the affected subsystem bits
- and restart. Thus we have a means for recovering from a dead encoder:
- Clear all bits that correspond to subsystems that we need to restart /
- reconfigure and start over.
-
-*/
-void pvr2_hdw_subsys_bit_chg_no_lock(struct pvr2_hdw *hdw,
- unsigned long msk,unsigned long val)
-{
- unsigned long nmsk;
- unsigned long vmsk;
- int ret;
- unsigned int tryCount = 0;
-
- if (!hdw->flag_ok) return;
-
- msk &= PVR2_SUBSYS_ALL;
-
- for (;;) {
- tryCount++;
- vmsk = hdw->subsys_enabled_mask & PVR2_SUBSYS_ALL;
- nmsk = (vmsk & ~msk) | (val & msk);
- if (!(nmsk ^ vmsk)) break;
- if (tryCount > 4) {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "Too many retries when configuring device;"
- " giving up");
- pvr2_hdw_render_useless(hdw);
- break;
- }
- if (tryCount > 1) {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "Retrying device reconfiguration");
- }
- pvr2_trace(PVR2_TRACE_INIT,
- "subsys mask changing 0x%lx:0x%lx"
- " from 0x%lx to 0x%lx",
- msk,val,hdw->subsys_enabled_mask,nmsk);
-
- vmsk = (nmsk ^ hdw->subsys_enabled_mask) &
- hdw->subsys_enabled_mask;
- if (vmsk) {
- if (vmsk & PVR2_SUBSYS_ENC_RUN) {
- pvr2_trace(PVR2_TRACE_CTL,
- "/*---TRACE_CTL----*/"
- " pvr2_encoder_stop");
- ret = pvr2_encoder_stop(hdw);
- if (ret) {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "Error recovery initiated");
- hdw->subsys_enabled_mask &=
- ~FIRMWARE_RECOVERY_BITS;
- continue;
- }
- }
- if (vmsk & PVR2_SUBSYS_USBSTREAM_RUN) {
- pvr2_trace(PVR2_TRACE_CTL,
- "/*---TRACE_CTL----*/"
- " pvr2_hdw_cmd_usbstream(0)");
- pvr2_hdw_cmd_usbstream(hdw,0);
- }
- if (vmsk & PVR2_SUBSYS_DIGITIZER_RUN) {
- pvr2_trace(PVR2_TRACE_CTL,
- "/*---TRACE_CTL----*/"
- " decoder disable");
- if (hdw->decoder_ctrl) {
- hdw->decoder_ctrl->enable(
- hdw->decoder_ctrl->ctxt,0);
- } else {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "WARNING:"
- " No decoder present");
- }
- hdw->subsys_enabled_mask &=
- ~PVR2_SUBSYS_DIGITIZER_RUN;
- }
- if (vmsk & PVR2_SUBSYS_CFG_ALL) {
- hdw->subsys_enabled_mask &=
- ~(vmsk & PVR2_SUBSYS_CFG_ALL);
- }
- }
- vmsk = (nmsk ^ hdw->subsys_enabled_mask) & nmsk;
- if (vmsk) {
- if (vmsk & PVR2_SUBSYS_ENC_FIRMWARE) {
- pvr2_trace(PVR2_TRACE_CTL,
- "/*---TRACE_CTL----*/"
- " pvr2_upload_firmware2");
- ret = pvr2_upload_firmware2(hdw);
- if (ret) {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "Failure uploading encoder"
- " firmware");
- pvr2_hdw_render_useless(hdw);
- break;
- }
- }
- if (vmsk & PVR2_SUBSYS_ENC_CFG) {
- pvr2_trace(PVR2_TRACE_CTL,
- "/*---TRACE_CTL----*/"
- " pvr2_encoder_configure");
- ret = pvr2_encoder_configure(hdw);
- if (ret) {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "Error recovery initiated");
- hdw->subsys_enabled_mask &=
- ~FIRMWARE_RECOVERY_BITS;
- continue;
- }
- }
- if (vmsk & PVR2_SUBSYS_DIGITIZER_RUN) {
- pvr2_trace(PVR2_TRACE_CTL,
- "/*---TRACE_CTL----*/"
- " decoder enable");
- if (hdw->decoder_ctrl) {
- hdw->decoder_ctrl->enable(
- hdw->decoder_ctrl->ctxt,!0);
- } else {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "WARNING:"
- " No decoder present");
- }
- hdw->subsys_enabled_mask |=
- PVR2_SUBSYS_DIGITIZER_RUN;
- }
- if (vmsk & PVR2_SUBSYS_USBSTREAM_RUN) {
- pvr2_trace(PVR2_TRACE_CTL,
- "/*---TRACE_CTL----*/"
- " pvr2_hdw_cmd_usbstream(1)");
- pvr2_hdw_cmd_usbstream(hdw,!0);
- }
- if (vmsk & PVR2_SUBSYS_ENC_RUN) {
- pvr2_trace(PVR2_TRACE_CTL,
- "/*---TRACE_CTL----*/"
- " pvr2_encoder_start");
- ret = pvr2_encoder_start(hdw);
- if (ret) {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "Error recovery initiated");
- hdw->subsys_enabled_mask &=
- ~FIRMWARE_RECOVERY_BITS;
- continue;
- }
- }
- }
- }
-}
-
-
-void pvr2_hdw_subsys_bit_chg(struct pvr2_hdw *hdw,
- unsigned long msk,unsigned long val)
-{
- LOCK_TAKE(hdw->big_lock); do {
- pvr2_hdw_subsys_bit_chg_no_lock(hdw,msk,val);
- } while (0); LOCK_GIVE(hdw->big_lock);
-}
-
-
-void pvr2_hdw_subsys_bit_set(struct pvr2_hdw *hdw,unsigned long msk)
-{
- pvr2_hdw_subsys_bit_chg(hdw,msk,msk);
-}
-
-
-void pvr2_hdw_subsys_bit_clr(struct pvr2_hdw *hdw,unsigned long msk)
-{
- pvr2_hdw_subsys_bit_chg(hdw,msk,0);
-}
-
-
-unsigned long pvr2_hdw_subsys_get(struct pvr2_hdw *hdw)
-{
- return hdw->subsys_enabled_mask;
-}
-
-
-unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *hdw)
-{
- return hdw->subsys_stream_mask;
-}
-
-
-void pvr2_hdw_subsys_stream_bit_chg_no_lock(struct pvr2_hdw *hdw,
- unsigned long msk,
- unsigned long val)
-{
- unsigned long val2;
- msk &= PVR2_SUBSYS_ALL;
- val2 = ((hdw->subsys_stream_mask & ~msk) | (val & msk));
- pvr2_trace(PVR2_TRACE_INIT,
- "stream mask changing 0x%lx:0x%lx from 0x%lx to 0x%lx",
- msk,val,hdw->subsys_stream_mask,val2);
- hdw->subsys_stream_mask = val2;
-}
-
-
-void pvr2_hdw_subsys_stream_bit_chg(struct pvr2_hdw *hdw,
- unsigned long msk,
- unsigned long val)
-{
- LOCK_TAKE(hdw->big_lock); do {
- pvr2_hdw_subsys_stream_bit_chg_no_lock(hdw,msk,val);
- } while (0); LOCK_GIVE(hdw->big_lock);
-}
-
-
-static int pvr2_ctl_get_streaming(struct pvr2_hdw *hdw,int ctl_id)
-{
- return hdw->flag_streaming_enabled != 0;
-}
-
-
-int pvr2_hdw_set_streaming_no_lock(struct pvr2_hdw *hdw,int enableFl)
-{
- if ((!enableFl) == !(hdw->flag_streaming_enabled)) return 0;
- if (enableFl) {
- pvr2_trace(PVR2_TRACE_START_STOP,
- "/*--TRACE_STREAM--*/ enable");
- pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,~0);
- } else {
- pvr2_trace(PVR2_TRACE_START_STOP,
- "/*--TRACE_STREAM--*/ disable");
- pvr2_hdw_subsys_bit_chg_no_lock(hdw,hdw->subsys_stream_mask,0);
- }
- if (!hdw->flag_ok) return -EIO;
- hdw->flag_streaming_enabled = enableFl != 0;
- return 0;
-}
-
-
-int pvr2_hdw_get_streaming(struct pvr2_hdw *hdw)
-{
- return hdw->flag_streaming_enabled != 0;
-}
-
-
-int pvr2_hdw_set_streaming(struct pvr2_hdw *hdw,int enable_flag)
-{
- int ret;
- LOCK_TAKE(hdw->big_lock); do {
- ret = pvr2_hdw_set_streaming_no_lock(hdw,enable_flag);
- } while (0); LOCK_GIVE(hdw->big_lock);
- return ret;
-}
-
-
-int pvr2_hdw_set_stream_type_no_lock(struct pvr2_hdw *hdw,
- enum pvr2_config config)
-{
- unsigned long sm = hdw->subsys_enabled_mask;
- if (!hdw->flag_ok) return -EIO;
- pvr2_hdw_subsys_bit_chg_no_lock(hdw,hdw->subsys_stream_mask,0);
- hdw->config = config;
- pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,sm);
- return 0;
-}
-
-
-int pvr2_hdw_set_stream_type(struct pvr2_hdw *hdw,enum pvr2_config config)
-{
- int ret;
- if (!hdw->flag_ok) return -EIO;
- LOCK_TAKE(hdw->big_lock);
- ret = pvr2_hdw_set_stream_type_no_lock(hdw,config);
- LOCK_GIVE(hdw->big_lock);
- return ret;
-}
-
-
-static int get_default_tuner_type(struct pvr2_hdw *hdw)
-{
- int unit_number = hdw->unit_number;
- int tp = -1;
- if ((unit_number >= 0) && (unit_number < PVR_NUM)) {
- tp = tuner[unit_number];
- }
- if (tp < 0) return -EINVAL;
- hdw->tuner_type = tp;
- return 0;
-}
-
-
-static unsigned int get_default_error_tolerance(struct pvr2_hdw *hdw)
-{
- int unit_number = hdw->unit_number;
- int tp = 0;
- if ((unit_number >= 0) && (unit_number < PVR_NUM)) {
- tp = tolerance[unit_number];
- }
- return tp;
-}
-
-
-static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
-{
- unsigned int idx;
- if (hdw->usb_intf->cur_altsetting->desc.bNumEndpoints == 0) {
- if (pvr2_upload_firmware1(hdw) != 0) {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "Failure uploading firmware1");
- }
- return;
- }
- hdw->fw1_state = FW1_STATE_OK;
-
- if (initusbreset) {
- pvr2_hdw_device_reset(hdw);
- }
- if (!pvr2_hdw_dev_ok(hdw)) return;
-
- pvr2_i2c_core_init(hdw);
- if (!pvr2_hdw_dev_ok(hdw)) return;
-
- if (pvr2_upload_firmware2(hdw)){
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,"device unstable!!");
- pvr2_hdw_render_useless(hdw);
- return;
- }
-
- for (idx = 0; idx < PVR2_CID_COUNT; idx++) {
- if (control_defs[idx].skip_init) continue;
- pvr2_hdw_set_ctl_value_internal(
- hdw,idx,control_defs[idx].default_value);
- }
-
- pvr2_reset_ctl_endpoints(hdw);
- if (!pvr2_hdw_dev_ok(hdw)) return;
-
- pvr2_eeprom_analyze(hdw);
- if (!pvr2_hdw_dev_ok(hdw)) return;
-
- if (!get_default_tuner_type(hdw)) {
- pvr2_trace(PVR2_TRACE_INIT,
- "pvr2_hdw_setup: Tuner type overridden to %d",
- hdw->tuner_type);
- }
-
- hdw->tuner_updated = !0;
- pvr2_i2c_core_check_stale(hdw);
- hdw->tuner_updated = 0;
-
- if (!pvr2_hdw_dev_ok(hdw)) return;
-
- pvr2_eeprom_set_default_standard(hdw);
- if (!pvr2_hdw_dev_ok(hdw)) return;
-
- pvr2_hdw_commit_ctl_internal(hdw);
- if (!pvr2_hdw_dev_ok(hdw)) return;
-
- hdw->vid_stream = pvr2_stream_create();
- if (!pvr2_hdw_dev_ok(hdw)) return;
- pvr2_trace(PVR2_TRACE_INIT,
- "pvr2_hdw_setup: video stream is %p",hdw->vid_stream);
- if (hdw->vid_stream) {
- idx = get_default_error_tolerance(hdw);
- if (idx) {
- pvr2_trace(PVR2_TRACE_INIT,
- "pvr2_hdw_setup: video stream %p"
- " setting tolerance %u",
- hdw->vid_stream,idx);
- }
- pvr2_stream_setup(hdw->vid_stream,hdw->usb_dev,
- PVR2_VID_ENDPOINT,idx);
- }
-
- if (!pvr2_hdw_dev_ok(hdw)) return;
-
- /* Make sure everything is up to date */
- pvr2_i2c_core_sync(hdw);
-
- if (!pvr2_hdw_dev_ok(hdw)) return;
-
- hdw->flag_init_ok = !0;
-}
-
-
-int pvr2_hdw_setup(struct pvr2_hdw *hdw)
-{
- pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_setup(hdw=%p) begin",hdw);
- LOCK_TAKE(hdw->big_lock); do {
- pvr2_hdw_setup_low(hdw);
- pvr2_trace(PVR2_TRACE_INIT,
- "pvr2_hdw_setup(hdw=%p) done, ok=%d init_ok=%d",
- hdw,hdw->flag_ok,hdw->flag_init_ok);
- if (pvr2_hdw_dev_ok(hdw)) {
- if (pvr2_hdw_init_ok(hdw)) {
- pvr2_trace(
- PVR2_TRACE_INFO,
- "Device initialization"
- " completed successfully.");
- break;
- }
- if (hdw->fw1_state == FW1_STATE_RELOAD) {
- pvr2_trace(
- PVR2_TRACE_INFO,
- "Device microcontroller firmware"
- " (re)loaded; it should now reset"
- " and reconnect.");
- break;
- }
- if (hdw->fw1_state == FW1_STATE_MISSING) {
- pvr2_trace(
- PVR2_TRACE_ERROR_LEGS,
- "***WARNING***"
- " Device microcontroller firmware"
- " seems to be missing.");
- pvr2_trace(
- PVR2_TRACE_ERROR_LEGS,
- "Did you install the pvrusb2 firmware"
- " files in their proper location?");
- break;
- }
- pvr2_trace(
- PVR2_TRACE_ERROR_LEGS,
- "Device initialization was not successful.");
- }
- if (procreload) {
- pvr2_trace(
- PVR2_TRACE_ERROR_LEGS,
- "Attempting pvrusb2 recovery by reloading"
- " primary firmware.");
- pvr2_trace(
- PVR2_TRACE_ERROR_LEGS,
- "If this works, device should disconnect"
- " and reconnect in a sane state.");
- hdw->fw1_state = FW1_STATE_UNKNOWN;
- pvr2_upload_firmware1(hdw);
- } else {
- pvr2_trace(
- PVR2_TRACE_ERROR_LEGS,
- "***WARNING*** pvrusb2 device hardware"
- " appears to be jammed"
- " and I can't clear it.");
- pvr2_trace(
- PVR2_TRACE_ERROR_LEGS,
- "You might need to power cycle"
- " the pvrusb2 device"
- " in order to recover.");
- }
- } while (0); LOCK_GIVE(hdw->big_lock);
- return hdw->flag_init_ok;
-}
-
-
-/* Create and return a structure for interacting with the underlying
- hardware */
-struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf)
-{
- unsigned int idx,cnt1,cnt2;
- struct pvr2_hdw *hdw;
- __u8 ifnum;
-
- hdw = kmalloc(sizeof(*hdw),GFP_KERNEL);
- pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_create: hdw=%p",hdw);
- if (!hdw) goto fail;
- memset(hdw,0,sizeof(*hdw));
- hdw->unit_number = -1;
- hdw->v4l_minor_number = -1;
- hdw->ctl_write_buffer = kmalloc(PVR2_CTL_BUFFSIZE,GFP_KERNEL);
- if (!hdw->ctl_write_buffer) goto fail;
- hdw->ctl_read_buffer = kmalloc(PVR2_CTL_BUFFSIZE,GFP_KERNEL);
- if (!hdw->ctl_read_buffer) goto fail;
- hdw->ctl_write_urb = usb_alloc_urb(0,GFP_KERNEL);
- if (!hdw->ctl_write_urb) goto fail;
- hdw->ctl_read_urb = usb_alloc_urb(0,GFP_KERNEL);
- if (!hdw->ctl_read_urb) goto fail;
-
- down(&pvr2_unit_sem); do {
- for (idx = 0; idx < PVR_NUM; idx++) {
- if (unit_pointers[idx]) continue;
- hdw->unit_number = idx;
- unit_pointers[idx] = hdw;
- break;
- }
- } while (0); up(&pvr2_unit_sem);
-
- cnt1 = 0;
- cnt2 = scnprintf(hdw->name+cnt1,sizeof(hdw->name)-cnt1,"pvrusb2");
- cnt1 += cnt2;
- if (hdw->unit_number >= 0) {
- cnt2 = scnprintf(hdw->name+cnt1,sizeof(hdw->name)-cnt1,"_%c",
- ('a' + hdw->unit_number));
- cnt1 += cnt2;
- }
- if (cnt1 >= sizeof(hdw->name)) cnt1 = sizeof(hdw->name)-1;
- hdw->name[cnt1] = 0;
-
- pvr2_trace(PVR2_TRACE_INIT,"Driver unit number is %d, name is %s",
- hdw->unit_number,hdw->name);
-
- hdw->tuner_type = -1;
- hdw->flag_ok = !0;
- /* Initialize the mask of subsystems that we will shut down when we
- stop streaming. */
- hdw->subsys_stream_mask = PVR2_SUBSYS_RUN_ALL;
- hdw->subsys_stream_mask |= PVR2_SUBSYS_ENC_CFG;
-
- pvr2_trace(PVR2_TRACE_INIT,"subsys_stream_mask: 0x%lx",
- hdw->subsys_stream_mask);
-
- hdw->usb_intf = intf;
- hdw->usb_dev = interface_to_usbdev(intf);
-
- ifnum = hdw->usb_intf->cur_altsetting->desc.bInterfaceNumber;
- usb_set_interface(hdw->usb_dev,ifnum,0);
-
- mutex_init(&hdw->ctl_lock_mutex);
- mutex_init(&hdw->big_lock_mutex);
-
- return hdw;
- fail:
- if (hdw) {
- if (hdw->ctl_read_urb) usb_free_urb(hdw->ctl_read_urb);
- if (hdw->ctl_write_urb) usb_free_urb(hdw->ctl_write_urb);
- if (hdw->ctl_read_buffer) kfree(hdw->ctl_read_buffer);
- if (hdw->ctl_write_buffer) kfree(hdw->ctl_write_buffer);
- kfree(hdw);
- }
- return 0;
-}
-
-
-/* Remove _all_ associations between this driver and the underlying USB
- layer. */
-void pvr2_hdw_remove_usb_stuff(struct pvr2_hdw *hdw)
-{
- if (hdw->flag_disconnected) return;
- pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_remove_usb_stuff: hdw=%p",hdw);
- if (hdw->ctl_read_urb) {
- usb_kill_urb(hdw->ctl_read_urb);
- usb_free_urb(hdw->ctl_read_urb);
- hdw->ctl_read_urb = 0;
- }
- if (hdw->ctl_write_urb) {
- usb_kill_urb(hdw->ctl_write_urb);
- usb_free_urb(hdw->ctl_write_urb);
- hdw->ctl_write_urb = 0;
- }
- if (hdw->ctl_read_buffer) {
- kfree(hdw->ctl_read_buffer);
- hdw->ctl_read_buffer = 0;
- }
- if (hdw->ctl_write_buffer) {
- kfree(hdw->ctl_write_buffer);
- hdw->ctl_write_buffer = 0;
- }
- pvr2_hdw_render_useless_unlocked(hdw);
- hdw->flag_disconnected = !0;
- hdw->usb_dev = 0;
- hdw->usb_intf = 0;
-}
-
-
-/* Destroy hardware interaction structure */
-void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
-{
- pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_destroy: hdw=%p",hdw);
- if (hdw->fw_buffer) {
- kfree(hdw->fw_buffer);
- hdw->fw_buffer = 0;
- }
- if (hdw->vid_stream) {
- pvr2_stream_destroy(hdw->vid_stream);
- hdw->vid_stream = 0;
- }
- if (hdw->audio_stat) {
- hdw->audio_stat->detach(hdw->audio_stat->ctxt);
- }
- if (hdw->decoder_ctrl) {
- hdw->decoder_ctrl->detach(hdw->decoder_ctrl->ctxt);
- }
- pvr2_i2c_core_done(hdw);
- pvr2_hdw_remove_usb_stuff(hdw);
- down(&pvr2_unit_sem); do {
- if ((hdw->unit_number >= 0) &&
- (hdw->unit_number < PVR_NUM) &&
- (unit_pointers[hdw->unit_number] == hdw)) {
- unit_pointers[hdw->unit_number] = 0;
- }
- } while (0); up(&pvr2_unit_sem);
- kfree(hdw);
-}
-
-
-int pvr2_hdw_init_ok(struct pvr2_hdw *hdw)
-{
- return hdw->flag_init_ok;
-}
-
-
-int pvr2_hdw_dev_ok(struct pvr2_hdw *hdw)
-{
- return (hdw && hdw->flag_ok);
-}
-
-
-/* Called when hardware has been unplugged */
-void pvr2_hdw_disconnect(struct pvr2_hdw *hdw)
-{
- pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_disconnect(hdw=%p)",hdw);
- LOCK_TAKE(hdw->big_lock);
- LOCK_TAKE(hdw->ctl_lock);
- pvr2_hdw_remove_usb_stuff(hdw);
- LOCK_GIVE(hdw->ctl_lock);
- LOCK_GIVE(hdw->big_lock);
-}
-
-
-static int pvr2_ctl_set_chanprog_id(struct pvr2_hdw *hdw,int ctl_id,int value)
-{
- /* This is a special case; the value to store is to an array, and
- the element to select is determined by PVR_CID_CHANPROG_ID. */
- int id = hdw->controls[PVR2_CID_CHANPROG_ID].value;
- if ((id < 1) || (id > FREQTABLE_SIZE)) return 0;
- hdw->freqTable[id-1] = value;
- if (hdw->controls[PVR2_CID_CHANNEL].value == id) {
- /* If the current channel happens to be the slot we just
- set, then act like the current channel just got changed
- so we'll update that too. */
- hdw->controls[PVR2_CID_CHANNEL].dirty = !0;
- }
- return 0;
-}
-
-
-static int pvr2_ctl_get_chanprog_id(struct pvr2_hdw *hdw,int ctl_id)
-{
- /* This is a special case; the value to return is from an array,
- and the element to select is determined by
- PVR_CID_CHANPROG_ID. */
- int id = hdw->controls[PVR2_CID_CHANPROG_ID].value;
- if ((id < 1) || (id > FREQTABLE_SIZE)) return 0;
- return hdw->freqTable[id-1];
-}
-
-
-/* Retrieve current value for a given control */
-int pvr2_hdw_get_ctl_value(struct pvr2_hdw *hdw,unsigned int ctl_id)
-{
- int ret = 0;
-
- if (ctl_id >= PVR2_CID_COUNT) return 0;
- LOCK_TAKE(hdw->big_lock); do {
- if (control_defs[ctl_id].get_func) {
- ret = control_defs[ctl_id].get_func(hdw,ctl_id);
- break;
- }
- ret = hdw->controls[ctl_id].value;
- } while(0); LOCK_GIVE(hdw->big_lock);
- return ret;
-}
-
-
-/* Return true if control is writable */
-int pvr2_hdw_get_ctl_rw(struct pvr2_hdw *hdw,unsigned int ctl_id)
-{
- if (ctl_id >= PVR2_CID_COUNT) return 0;
- if (control_defs[ctl_id].get_func && !control_defs[ctl_id].set_func) {
- return 0;
- }
- return !0;
-}
-
-
-/* Retrieve legal minimum value for a given control */
-int pvr2_hdw_get_ctl_min_value(struct pvr2_hdw *hdw,unsigned int ctl_id)
-{
- if (ctl_id >= PVR2_CID_COUNT) return 0;
- return control_defs[ctl_id].min_value;
-}
-
-
-/* Retrieve legal maximum value for a given control */
-int pvr2_hdw_get_ctl_max_value(struct pvr2_hdw *hdw,unsigned int ctl_id)
-{
- if (ctl_id >= PVR2_CID_COUNT) return 0;
- return control_defs[ctl_id].max_value;
-}
-
-
-/* Set current value for given control - normally this is just stored and
- the hardware isn't updated until the commit function is called. */
-int pvr2_hdw_set_ctl_value_internal(struct pvr2_hdw *hdw,
- unsigned int ctl_id,int value)
-{
- if (ctl_id >= PVR2_CID_COUNT) return -EINVAL;
- if (value < control_defs[ctl_id].min_value) return -EINVAL;
- if (value > control_defs[ctl_id].max_value) return -EINVAL;
- if (control_defs[ctl_id].set_func) {
- return control_defs[ctl_id].set_func(hdw,ctl_id,value);
- } else if (control_defs[ctl_id].get_func) {
- /* If there's no "set" function yet there is still a "get"
- function, then treat this as a read-only value. */
- return -EINVAL;
- }
- if ((hdw->controls[ctl_id].value != value) || (ctlchg != 0)) {
- hdw->controls[ctl_id].value = value;
- hdw->controls[ctl_id].dirty = !0;
- }
- return 0;
-}
-
-
-/* Set current value for given control - this is just stored; the hardware
- isn't updated until the commit function is called. */
-int pvr2_hdw_set_ctl_value(struct pvr2_hdw *hdw,unsigned int ctl_id,int value)
-{
- int ret;
- LOCK_TAKE(hdw->big_lock); do {
- ret = pvr2_hdw_set_ctl_value_internal(hdw,ctl_id,value);
- } while (0); LOCK_GIVE(hdw->big_lock);
- return ret;
-}
-
-
-/* Retrieve string name for a given control value (returns a null pointer
- for any invalid combinations). */
-const char *pvr2_hdw_get_ctl_value_name(struct pvr2_hdw *hdw,
- unsigned int ctl_id,
- int value)
-{
- struct pvr2_ctl_def *cdef;
- if (ctl_id >= PVR2_CID_COUNT) return 0;
- cdef = control_defs + ctl_id;
- if (! cdef->value_defs_ptr) return 0;
- if (value >= cdef->value_defs_count) return 0;
- return cdef->value_defs_ptr[value];
-}
-
-
-/* Retrieve string name for given control */
-const char *pvr2_hdw_get_ctl_name(struct pvr2_hdw *hdw,unsigned int ctl_id)
-{
- if (ctl_id >= PVR2_CID_COUNT) return 0;
- return control_defs[ctl_id].name;
-}
-
-
-/* Commit all control changes made up to this point. Subsystems can be
- indirectly affected by these changes. For a given set of things being
- committed, we'll clear the affected subsystem bits and then once we're
- done committing everything we'll make a request to restore the subsystem
- state(s) back to their previous value before this function was called.
- Thus we can automatically reconfigure affected pieces of the driver as
- controls are changed. */
-int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
-{
- unsigned long saved_subsys_mask = hdw->subsys_enabled_mask;
- unsigned long stale_subsys_mask = 0;
- unsigned int idx;
- int value;
- const char *ctl_name;
- const char *ctl_value;
- int commit_flag = 0;
-
- /* Let's see if the channel changed and we have to update the
- frequency because of it. This setup means one can tune the
- receiver either by just setting the channel (using the frequency
- table), or by directly programming the frequency. How do we
- resolve the obvious conflict here? The direct frequency takes
- priority; if directly set then we commit that value and force
- the channel to zero which is interpreted to mean "none". If on
- the other hand we see that the channel has been set and it's a
- legal value, then we copy that into the frequency. The metaphor
- here is similar to when you tune your digital radio: You an
- either set a frequency directly or punch up a pre-programmed
- station. Either way a frequency is set, and if you do use a
- preset, then the radio also shows you which preset it is - until
- you override that by directly entering a new frequency. */
- if (hdw->controls[PVR2_CID_FREQUENCY].dirty) {
- /* Frequency has been directly set, so clear out the
- channel. */
- hdw->controls[PVR2_CID_CHANNEL].value = 0;
- } else if (hdw->controls[PVR2_CID_CHANNEL].dirty) {
- int id = hdw->controls[PVR2_CID_CHANNEL].value;
- if ((id > 0) && (id <= FREQTABLE_SIZE)) {
- if (hdw->controls[PVR2_CID_FREQUENCY].value !=
- hdw->freqTable[id-1]) {
- hdw->controls[PVR2_CID_FREQUENCY].value =
- hdw->freqTable[id-1];
- hdw->controls[PVR2_CID_FREQUENCY].dirty = !0;
- }
- }
- }
-
- for (idx = 0; idx < PVR2_CID_COUNT; idx++) {
- if (!hdw->controls[idx].dirty) continue;
- if (!commit_flag) {
- commit_flag = !0;
- }
- value = hdw->controls[idx].value;
- ctl_name = control_defs[idx].name;
- if (control_defs[idx].value_defs_ptr) {
- if (value < control_defs[idx].value_defs_count) {
- ctl_value =
- control_defs[idx].value_defs_ptr[value];
- } else {
- ctl_value = "<out of range>";
- }
- } else {
- ctl_value = "<integer>";
- }
- pvr2_trace(PVR2_TRACE_CTL,
- "/*--TRACE_COMMIT--*/ \"%s\" <-- %d (%s)",
- ctl_name,value,ctl_value);
- }
-
- if (!commit_flag) {
- /* Nothing has changed */
- return 0;
- }
-
- /* When video standard changes, reset the hres and vres values -
- but if the user has pending changes there, then let the changes
- take priority. */
- if (hdw->controls[PVR2_CID_VIDEOSTANDARD].dirty) {
- /* Rewrite the vertical resolution to be appropriate to the
- video standard that has been selected. */
- int nvres = hdw->controls[PVR2_CID_VRES].value;
- switch (hdw->controls[PVR2_CID_VIDEOSTANDARD].value) {
- case PVR2_CVAL_VIDEOSTANDARD_NTSC_M:
- case PVR2_CVAL_VIDEOSTANDARD_PAL_M:
- nvres = 480;
- break;
- default:
- nvres = 576;
- }
- if (nvres != hdw->controls[PVR2_CID_VRES].value) {
- hdw->controls[PVR2_CID_VRES].value = nvres;
- hdw->controls[PVR2_CID_VRES].dirty = !0;
- }
- if (!hdw->controls[PVR2_CID_INTERLACE].value) {
- hdw->controls[PVR2_CID_INTERLACE].value = 0;
- hdw->controls[PVR2_CID_INTERLACE].dirty = !0;
- }
- }
-
- if (hdw->controls[PVR2_CID_VIDEOSTANDARD].dirty ||
- hdw->controls[PVR2_CID_VRES].dirty ||
- hdw->controls[PVR2_CID_HRES].dirty ||
- hdw->controls[PVR2_CID_INTERLACE].dirty ||
- hdw->controls[PVR2_CID_VBR].dirty ||
- hdw->controls[PVR2_CID_AVERAGEVIDEOBITRATE].dirty ||
- hdw->controls[PVR2_CID_PEAKVIDEOBITRATE].dirty ||
- hdw->controls[PVR2_CID_AUDIOBITRATE].dirty ||
- hdw->controls[PVR2_CID_SRATE].dirty ||
- hdw->controls[PVR2_CID_AUDIOLAYER].dirty ||
- hdw->controls[PVR2_CID_AUDIOCRC].dirty ||
- hdw->controls[PVR2_CID_AUDIOEMPHASIS].dirty) {
- /* If any of this changes, then the encoder needs to be
- reconfigured, and we need to reset the stream. */
- stale_subsys_mask |= PVR2_SUBSYS_ENC_CFG;
- stale_subsys_mask |= hdw->subsys_stream_mask;
- }
-
- /* Scan i2c core at this point - before we clear all the dirty
- bits. Various parts of the i2c core will notice dirty bits as
- appropriate and arrange to broadcast or directly send updates to
- the client drivers in order to keep everything in sync */
- pvr2_i2c_core_check_stale(hdw);
-
- for (idx = 0; idx < PVR2_CID_COUNT; idx++) {
- hdw->controls[idx].dirty = 0;
- }
-
- /* Now execute i2c core update */
- pvr2_i2c_core_sync(hdw);
-
- pvr2_hdw_subsys_bit_chg_no_lock(hdw,stale_subsys_mask,0);
- pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,saved_subsys_mask);
-
- return 0;
-}
-
-
-int pvr2_hdw_commit_ctl(struct pvr2_hdw *hdw)
-{
- LOCK_TAKE(hdw->big_lock); do {
- pvr2_hdw_commit_ctl_internal(hdw);
- } while (0); LOCK_GIVE(hdw->big_lock);
- return 0;
-}
-
-
-void pvr2_hdw_poll(struct pvr2_hdw *hdw)
-{
- LOCK_TAKE(hdw->big_lock); do {
- pvr2_i2c_core_sync(hdw);
- } while (0); LOCK_GIVE(hdw->big_lock);
-}
-
-
-void pvr2_hdw_setup_poll_trigger(struct pvr2_hdw *hdw,
- void (*func)(void *),
- void *data)
-{
- LOCK_TAKE(hdw->big_lock); do {
- hdw->poll_trigger_func = func;
- hdw->poll_trigger_data = data;
- } while (0); LOCK_GIVE(hdw->big_lock);
-}
-
-
-void pvr2_hdw_poll_trigger_unlocked(struct pvr2_hdw *hdw)
-{
- if (hdw->poll_trigger_func) {
- hdw->poll_trigger_func(hdw->poll_trigger_data);
- }
-}
-
-
-void pvr2_hdw_poll_trigger(struct pvr2_hdw *hdw)
-{
- LOCK_TAKE(hdw->big_lock); do {
- pvr2_hdw_poll_trigger_unlocked(hdw);
- } while (0); LOCK_GIVE(hdw->big_lock);
-}
-
-
-/* Find out how many controls there are. Legal ids are numbered from 1
- through this value. */
-unsigned int pvr2_hdw_get_ctl_count(struct pvr2_hdw *hdw)
-{
- return PVR2_CID_COUNT;
-}
-
-
-/* Return name for this driver instance */
-const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw)
-{
- return hdw->name;
-}
-
-
-/* Return bit mask indicating signal status */
-unsigned int pvr2_hdw_get_signal_status_internal(struct pvr2_hdw *hdw)
-{
- unsigned int msk = 0;
- switch (hdw->controls[PVR2_CID_INPUT].value) {
- case PVR2_CVAL_INPUT_TV:
- case PVR2_CVAL_INPUT_RADIO:
- if (hdw->decoder_ctrl &&
- hdw->decoder_ctrl->tuned(hdw->decoder_ctrl->ctxt)) {
- msk |= PVR2_SIGNAL_OK;
- if (hdw->audio_stat &&
- hdw->audio_stat->status(hdw->audio_stat->ctxt)) {
- if (hdw->flag_stereo) {
- msk |= PVR2_SIGNAL_STEREO;
- }
- if (hdw->flag_bilingual) {
- msk |= PVR2_SIGNAL_SAP;
- }
- }
- }
- break;
- default:
- msk |= PVR2_SIGNAL_OK | PVR2_SIGNAL_STEREO;
- }
- return msk;
-}
-
-
-static int pvr2_ctl_get_subsys_mask(struct pvr2_hdw *hdw,int ctl_id)
-{
- return hdw->subsys_enabled_mask;
-}
-
-
-static int pvr2_ctl_set_subsys_mask(struct pvr2_hdw *hdw,int ctl_id,int val)
-{
- pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,val);
- return 0;
-}
-
-
-static int pvr2_ctl_get_subsys_stream_mask(struct pvr2_hdw *hdw,int ctl_id)
-{
- return hdw->subsys_stream_mask;
-}
-
-
-static int pvr2_ctl_set_subsys_stream_mask(struct pvr2_hdw *hdw,int ctl_id,
- int val)
-{
- pvr2_hdw_subsys_stream_bit_chg_no_lock(hdw,~0,val);
- return 0;
-}
-
-
-static int pvr2_ctl_get_hsm(struct pvr2_hdw *hdw,int ctl_id)
-{
- int result = pvr2_hdw_is_hsm(hdw);
- if (result < 0) return PVR2_CVAL_HSM_FAIL;
- if (result) return PVR2_CVAL_HSM_HIGH;
- return PVR2_CVAL_HSM_FULL;
-}
-
-
-int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw)
-{
- int result;
- LOCK_TAKE(hdw->ctl_lock); do {
- hdw->cmd_buffer[0] = 0x0b;
- result = pvr2_send_request(hdw,
- hdw->cmd_buffer,1,
- hdw->cmd_buffer,1);
- if (result < 0) break;
- result = (hdw->cmd_buffer[0] != 0);
- } while(0); LOCK_GIVE(hdw->ctl_lock);
- return result;
-}
-
-
-static int pvr2_ctl_get_signal(struct pvr2_hdw *hdw,int ctl_id)
-{
- return ((pvr2_hdw_get_signal_status_internal(hdw) & PVR2_SIGNAL_OK) ?
- 1 : 0);
-}
-
-
-/* Return bit mask indicating signal status */
-unsigned int pvr2_hdw_get_signal_status(struct pvr2_hdw *hdw)
-{
- unsigned int msk = 0;
- LOCK_TAKE(hdw->big_lock); do {
- msk = pvr2_hdw_get_signal_status_internal(hdw);
- } while (0); LOCK_GIVE(hdw->big_lock);
- return msk;
-}
-
-
-/* Get handle to video output stream */
-struct pvr2_stream *pvr2_hdw_get_video_stream(struct pvr2_hdw *hp)
-{
- return hp->vid_stream;
-}
-
-
-void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, int enable_flag)
-{
- int ret;
- u16 address;
- unsigned int pipe;
- LOCK_TAKE(hdw->big_lock); do {
- if ((hdw->fw_buffer == 0) == !enable_flag) break;
-
- if (!enable_flag) {
- pvr2_trace(PVR2_TRACE_FIRMWARE,
- "Cleaning up after CPU firmware fetch");
- kfree(hdw->fw_buffer);
- hdw->fw_buffer = 0;
- hdw->fw_size = 0;
- /* Now release the CPU. It will disconnect and
- reconnect later. */
- pvr2_hdw_cpureset_assert(hdw,0);
- break;
- }
-
- pvr2_trace(PVR2_TRACE_FIRMWARE,
- "Preparing to suck out CPU firmware");
- hdw->fw_size = 0x2000;
- hdw->fw_buffer = kmalloc(hdw->fw_size,GFP_KERNEL);
- if (!hdw->fw_buffer) {
- hdw->fw_size = 0;
- break;
- }
-
- memset(hdw->fw_buffer,0,hdw->fw_size);
-
- /* We have to hold the CPU during firmware upload. */
- pvr2_hdw_cpureset_assert(hdw,1);
-
- /* download the firmware from address 0000-1fff in 2048
- (=0x800) bytes chunk. */
-
- pvr2_trace(PVR2_TRACE_FIRMWARE,"Grabbing CPU firmware");
- pipe = usb_rcvctrlpipe(hdw->usb_dev, 0);
- for(address = 0; address < hdw->fw_size; address += 0x800) {
- ret = usb_control_msg(hdw->usb_dev,pipe,0xa0,0xc0,
- address,0,
- hdw->fw_buffer+address,0x800,HZ);
- if (ret < 0) break;
- }
-
- pvr2_trace(PVR2_TRACE_FIRMWARE,"Done grabbing CPU firmware");
-
- } while (0); LOCK_GIVE(hdw->big_lock);
-}
-
-
-/* Return true if we're in a mode for retrieval CPU firmware */
-int pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *hdw)
-{
- return hdw->fw_buffer != 0;
-}
-
-
-int pvr2_hdw_cpufw_get(struct pvr2_hdw *hdw,unsigned int offs,
- char *buf,unsigned int cnt)
-{
- int ret = -EINVAL;
- LOCK_TAKE(hdw->big_lock); do {
- if (!buf) break;
- if (!cnt) break;
-
- if (!hdw->fw_buffer) {
- ret = -EIO;
- break;
- }
-
- if (offs >= hdw->fw_size) {
- pvr2_trace(PVR2_TRACE_FIRMWARE,
- "Read firmware data offs=%d EOF",
- offs);
- ret = 0;
- break;
- }
-
- if (offs + cnt > hdw->fw_size) cnt = hdw->fw_size - offs;
-
- memcpy(buf,hdw->fw_buffer+offs,cnt);
-
- pvr2_trace(PVR2_TRACE_FIRMWARE,
- "Read firmware data offs=%d cnt=%d",
- offs,cnt);
- ret = cnt;
- } while (0); LOCK_GIVE(hdw->big_lock);
-
- return ret;
-}
-
-
-int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *hdw)
-{
- return hdw->v4l_minor_number;
-}
-
-
-/* Store the v4l minor device number */
-void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *hdw,int v)
-{
- hdw->v4l_minor_number = v;
-}
-
-
-void pvr2_reset_ctl_endpoints(struct pvr2_hdw *hdw)
-{
- if (!hdw->usb_dev) return;
- usb_settoggle(hdw->usb_dev, PVR2_CTL_WRITE_ENDPOINT & 0xf,
- !(PVR2_CTL_WRITE_ENDPOINT & USB_DIR_IN), 0);
- usb_settoggle(hdw->usb_dev, PVR2_CTL_READ_ENDPOINT & 0xf,
- !(PVR2_CTL_READ_ENDPOINT & USB_DIR_IN), 0);
- usb_clear_halt(hdw->usb_dev,
- usb_rcvbulkpipe(hdw->usb_dev,
- PVR2_CTL_READ_ENDPOINT & 0x7f));
- usb_clear_halt(hdw->usb_dev,
- usb_sndbulkpipe(hdw->usb_dev,
- PVR2_CTL_WRITE_ENDPOINT & 0x7f));
-}
-
-
-static void pvr2_ctl_write_complete(struct urb *urb, struct pt_regs *regs)
-{
- struct pvr2_hdw *hdw = urb->context;
- hdw->ctl_write_pend_flag = 0;
- if (hdw->ctl_read_pend_flag) return;
- complete(&hdw->ctl_done);
-}
-
-
-static void pvr2_ctl_read_complete(struct urb *urb, struct pt_regs *regs)
-{
- struct pvr2_hdw *hdw = urb->context;
- hdw->ctl_read_pend_flag = 0;
- if (hdw->ctl_write_pend_flag) return;
- complete(&hdw->ctl_done);
-}
-
-
-static void pvr2_ctl_timeout(unsigned long data)
-{
- struct pvr2_hdw *hdw = (struct pvr2_hdw *)data;
- if (hdw->ctl_write_pend_flag || hdw->ctl_read_pend_flag) {
- hdw->ctl_timeout_flag = !0;
- if (hdw->ctl_write_pend_flag && hdw->ctl_write_urb) {
- usb_unlink_urb(hdw->ctl_write_urb);
- }
- if (hdw->ctl_read_pend_flag && hdw->ctl_read_urb) {
- usb_unlink_urb(hdw->ctl_read_urb);
- }
- }
-}
-
-
-int pvr2_send_request(struct pvr2_hdw *hdw,
- void *write_data,unsigned int write_len,
- void *read_data,unsigned int read_len)
-{
- unsigned int idx;
- int status;
- struct timer_list timer;
- if (!hdw->ctl_lock_held) {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "Attempted to execute control transfer"
- " without lock!!");
- status = -EINVAL;
- goto done;
- }
- if (!hdw->flag_ok) {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "Attempted to execute control transfer"
- " when device not ok");
- return -EIO;
- }
- if (!(hdw->ctl_read_urb && hdw->ctl_write_urb)) {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "Attempted to execute control transfer"
- " when USB is disconnected");
- return -EIO;
- }
-
- /* Ensure that we have sane parameters */
- if (!write_data) write_len = 0;
- if (!read_data) read_len = 0;
- if (write_len > PVR2_CTL_BUFFSIZE) {
- pvr2_trace(
- PVR2_TRACE_ERROR_LEGS,
- "Attempted to execute %d byte"
- " control-write transfer (limit=%d)",
- write_len,PVR2_CTL_BUFFSIZE);
- return -EINVAL;
- }
- if (read_len > PVR2_CTL_BUFFSIZE) {
- pvr2_trace(
- PVR2_TRACE_ERROR_LEGS,
- "Attempted to execute %d byte"
- " control-read transfer (limit=%d)",
- write_len,PVR2_CTL_BUFFSIZE);
- return -EINVAL;
- }
- if ((!write_len) && (!read_len)) {
- pvr2_trace(
- PVR2_TRACE_ERROR_LEGS,
- "Attempted to execute null control transfer?");
- return -EINVAL;
- }
-
- hdw->cmd_debug_state = 1;
- if (write_len) {
- hdw->cmd_debug_code = ((unsigned char *)write_data)[0];
- } else {
- hdw->cmd_debug_code = 0;
- }
- hdw->cmd_debug_write_len = write_len;
- hdw->cmd_debug_read_len = read_len;
-
- /* Initialize common stuff */
- init_completion(&hdw->ctl_done);
- hdw->ctl_timeout_flag = 0;
- hdw->ctl_write_pend_flag = 0;
- hdw->ctl_read_pend_flag = 0;
- init_timer(&timer);
- timer.expires = jiffies + HZ*4;
- timer.data = (unsigned long)hdw;
- timer.function = pvr2_ctl_timeout;
-
- if (write_len) {
- hdw->cmd_debug_state = 2;
- /* Transfer write data to internal buffer */
- for (idx = 0; idx < write_len; idx++) {
- hdw->ctl_write_buffer[idx] =
- ((unsigned char *)write_data)[idx];
- }
- /* Initiate a write request */
- usb_fill_bulk_urb(hdw->ctl_write_urb,
- hdw->usb_dev,
- usb_sndbulkpipe(hdw->usb_dev,
- PVR2_CTL_WRITE_ENDPOINT),
- hdw->ctl_write_buffer,
- write_len,
- pvr2_ctl_write_complete,
- hdw);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
- hdw->ctl_write_urb->transfer_flags |= URB_ASYNC_UNLINK;
-#endif
- hdw->ctl_write_urb->actual_length = 0;
- hdw->ctl_write_pend_flag = !0;
- status = usb_submit_urb(hdw->ctl_write_urb,GFP_KERNEL);
- if (status < 0) {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "Failed to submit write-control"
- " URB status=%d",status);
- hdw->ctl_write_pend_flag = 0;
- }
- }
-
- if (read_len) {
- hdw->cmd_debug_state = 3;
- memset(hdw->ctl_read_buffer,0x43,read_len);
- /* Initiate a read request */
- usb_fill_bulk_urb(hdw->ctl_read_urb,
- hdw->usb_dev,
- usb_rcvbulkpipe(hdw->usb_dev,
- PVR2_CTL_READ_ENDPOINT),
- hdw->ctl_read_buffer,
- read_len,
- pvr2_ctl_read_complete,
- hdw);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
- hdw->ctl_read_urb->transfer_flags |= URB_ASYNC_UNLINK;
-#endif
- hdw->ctl_read_urb->actual_length = 0;
- hdw->ctl_read_pend_flag = !0;
- status = usb_submit_urb(hdw->ctl_read_urb,GFP_KERNEL);
- if (status < 0) {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "Failed to submit read-control"
- " URB status=%d",status);
- hdw->ctl_read_pend_flag = 0;
- }
- }
-
- /* Start timer */
- add_timer(&timer);
-
- /* Now wait for all I/O to complete */
- hdw->cmd_debug_state = 4;
- while (hdw->ctl_write_pend_flag || hdw->ctl_read_pend_flag) {
- wait_for_completion(&hdw->ctl_done);
- }
- hdw->cmd_debug_state = 5;
-
- /* Stop timer */
- del_timer_sync(&timer);
-
- hdw->cmd_debug_state = 6;
- status = 0;
-
- if (hdw->ctl_timeout_flag) {
- status = -ETIMEDOUT;
- goto done;
- }
-
- if (write_len) {
- /* Validate results of write request */
- if ((hdw->ctl_write_urb->status != 0) &&
- (hdw->ctl_write_urb->status != -ENOENT) &&
- (hdw->ctl_write_urb->status != -ESHUTDOWN) &&
- (hdw->ctl_write_urb->status != -ECONNRESET)) {
- /* USB subsystem is reporting some kind of failure
- on the write */
- status = hdw->ctl_write_urb->status;
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "control-write URB failure, status=%d",
- status);
- goto done;
- }
- if (hdw->ctl_write_urb->actual_length < write_len) {
- /* Failed to write enough data */
- status = -EIO;
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "control-write URB short,"
- " expected=%d got=%d",
- write_len,
- hdw->ctl_write_urb->actual_length);
- goto done;
- }
- }
- if (read_len) {
- /* Validate results of read request */
- if ((hdw->ctl_read_urb->status != 0) &&
- (hdw->ctl_read_urb->status != -ENOENT) &&
- (hdw->ctl_read_urb->status != -ESHUTDOWN) &&
- (hdw->ctl_read_urb->status != -ECONNRESET)) {
- /* USB subsystem is reporting some kind of failure
- on the read */
- status = hdw->ctl_read_urb->status;
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "control-read URB failure, status=%d",
- status);
- goto done;
- }
- if (hdw->ctl_read_urb->actual_length < read_len) {
- /* Failed to read enough data */
- status = -EIO;
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "control-read URB short,"
- " expected=%d got=%d",
- read_len,hdw->ctl_read_urb->actual_length);
- goto done;
- }
- /* Transfer retrieved data out from internal buffer */
- for (idx = 0; idx < read_len; idx++) {
- ((unsigned char *)read_data)[idx] =
- hdw->ctl_read_buffer[idx];
- }
- }
-
- done:
- hdw->cmd_debug_state = 0;
- if (status < 0) {
- pvr2_hdw_render_useless_unlocked(hdw);
- }
- return status;
-}
-
-
-int pvr2_write_register(struct pvr2_hdw *hdw, u16 reg, u32 data)
-{
- int ret;
-
- LOCK_TAKE(hdw->ctl_lock);
-
- hdw->cmd_buffer[0] = 0x04; /* write register prefix */
- PVR2_DECOMPOSE_LE(hdw->cmd_buffer,1,data);
- hdw->cmd_buffer[5] = 0;
- hdw->cmd_buffer[6] = (reg >> 8) & 0xff;
- hdw->cmd_buffer[7] = reg & 0xff;
-
-
- ret = pvr2_send_request(hdw, hdw->cmd_buffer, 8, hdw->cmd_buffer, 0);
-
- LOCK_GIVE(hdw->ctl_lock);
-
- return ret;
-}
-
-
-int pvr2_read_register(struct pvr2_hdw *hdw, u16 reg, u32 *data)
-{
- int ret = 0;
-
- LOCK_TAKE(hdw->ctl_lock);
-
- hdw->cmd_buffer[0] = 0x05; /* read register prefix */
- hdw->cmd_buffer[1] = 0;
- hdw->cmd_buffer[2] = 0;
- hdw->cmd_buffer[3] = 0;
- hdw->cmd_buffer[4] = 0;
- hdw->cmd_buffer[5] = 0;
- hdw->cmd_buffer[6] = (reg >> 8) & 0xff;
- hdw->cmd_buffer[7] = reg & 0xff;
-
- ret |= pvr2_send_request(hdw, hdw->cmd_buffer, 8, hdw->cmd_buffer, 4);
- *data = PVR2_COMPOSE_LE(hdw->cmd_buffer,0);
-
- LOCK_GIVE(hdw->ctl_lock);
-
- return ret;
-}
-
-
-int pvr2_write_u16(struct pvr2_hdw *hdw, u16 data, int res)
-{
- int ret;
-
- LOCK_TAKE(hdw->ctl_lock);
-
- hdw->cmd_buffer[0] = (data >> 8) & 0xff;
- hdw->cmd_buffer[1] = data & 0xff;
-
- ret = pvr2_send_request(hdw, hdw->cmd_buffer, 2, hdw->cmd_buffer, res);
-
- LOCK_GIVE(hdw->ctl_lock);
-
- return ret;
-}
-
-
-int pvr2_write_u8(struct pvr2_hdw *hdw, u8 data, int res)
-{
- int ret;
-
- LOCK_TAKE(hdw->ctl_lock);
-
- hdw->cmd_buffer[0] = data;
-
- ret = pvr2_send_request(hdw, hdw->cmd_buffer, 1, hdw->cmd_buffer, res);
-
- LOCK_GIVE(hdw->ctl_lock);
-
- return ret;
-}
-
-
-void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *hdw)
-{
- if (!hdw->flag_ok) return;
- pvr2_trace(PVR2_TRACE_INIT,"render_useless");
- hdw->flag_ok = 0;
- if (hdw->vid_stream) {
- pvr2_stream_setup(hdw->vid_stream,0,0,0);
- }
- hdw->flag_streaming_enabled = 0;
- hdw->subsys_enabled_mask = 0;
-}
-
-
-void pvr2_hdw_render_useless(struct pvr2_hdw *hdw)
-{
- LOCK_TAKE(hdw->ctl_lock);
- pvr2_hdw_render_useless_unlocked(hdw);
- LOCK_GIVE(hdw->ctl_lock);
-}
-
-
-void pvr2_hdw_device_reset(struct pvr2_hdw *hdw)
-{
- int ret;
- pvr2_trace(PVR2_TRACE_INIT,"Performing a device reset...");
- ret = usb_lock_device_for_reset(hdw->usb_dev,0);
- if (ret == 1) {
- ret = usb_reset_device(hdw->usb_dev);
- usb_unlock_device(hdw->usb_dev);
- } else {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "Failed to lock USB device ret=%d",ret);
- }
-}
-
-
-void pvr2_hdw_cpureset_assert(struct pvr2_hdw *hdw,int val)
-{
- char da[1];
- unsigned int pipe;
- int ret;
-
- if (!hdw->usb_dev) return;
-
- pvr2_trace(PVR2_TRACE_INIT,"cpureset_assert(%d)",val);
-
- da[0] = val ? 0x01 : 0x00;
-
- /* Write the CPUCS register on the 8051. The lsb of the register
- is the reset bit; a 1 asserts reset while a 0 clears it. */
- pipe = usb_sndctrlpipe(hdw->usb_dev, 0);
- ret = usb_control_msg(hdw->usb_dev,pipe,0xa0,0x40,0xe600,0,da,1,HZ);
- if (ret < 0) {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "cpureset_assert(%d) error=%d",val,ret);
- pvr2_hdw_render_useless(hdw);
- }
-}
-
-
-int pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *hdw)
-{
- int status;
- LOCK_TAKE(hdw->ctl_lock); do {
- pvr2_trace(PVR2_TRACE_INIT,"Requesting uproc hard reset");
- hdw->flag_ok = !0;
- hdw->cmd_buffer[0] = 0xdd;
- status = pvr2_send_request(hdw,hdw->cmd_buffer,1,0,0);
- } while (0); LOCK_GIVE(hdw->ctl_lock);
- return status;
-}
-
-
-int pvr2_hdw_cmd_soft_reset(struct pvr2_hdw *hdw)
-{
- int status;
- LOCK_TAKE(hdw->ctl_lock); do {
- pvr2_trace(PVR2_TRACE_INIT,"Requesting uproc soft reset");
- hdw->cmd_buffer[0] = 0xde;
- status = pvr2_send_request(hdw,hdw->cmd_buffer,1,0,0);
- } while (0); LOCK_GIVE(hdw->ctl_lock);
- return status;
-}
-
-
-int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl)
-{
- int status;
- LOCK_TAKE(hdw->ctl_lock); do {
- hdw->cmd_buffer[0] = (runFl ? 0x36 : 0x37);
- status = pvr2_send_request(hdw,hdw->cmd_buffer,1,0,0);
- } while (0); LOCK_GIVE(hdw->ctl_lock);
- if (!status) {
- hdw->subsys_enabled_mask =
- ((hdw->subsys_enabled_mask &
- ~PVR2_SUBSYS_USBSTREAM_RUN) |
- (runFl ? PVR2_SUBSYS_USBSTREAM_RUN : 0));
- }
- return status;
-}
-
-
-void pvr2_hdw_get_debug_info(const struct pvr2_hdw *hdw,
- struct pvr2_hdw_debug_info *ptr)
-{
- ptr->big_lock_held = hdw->big_lock_held;
- ptr->ctl_lock_held = hdw->ctl_lock_held;
- ptr->flag_ok = hdw->flag_ok;
- ptr->flag_disconnected = hdw->flag_disconnected;
- ptr->flag_init_ok = hdw->flag_init_ok;
- ptr->flag_streaming_enabled = hdw->flag_streaming_enabled;
- ptr->subsys_flags = hdw->subsys_enabled_mask;
- ptr->cmd_debug_state = hdw->cmd_debug_state;
- ptr->cmd_code = hdw->cmd_debug_code;
- ptr->cmd_debug_write_len = hdw->cmd_debug_write_len;
- ptr->cmd_debug_read_len = hdw->cmd_debug_read_len;
- ptr->cmd_debug_timeout = hdw->ctl_timeout_flag;
- ptr->cmd_debug_write_pend = hdw->ctl_write_pend_flag;
- ptr->cmd_debug_read_pend = hdw->ctl_read_pend_flag;
- ptr->cmd_debug_rstatus = hdw->ctl_read_urb->status;
- ptr->cmd_debug_wstatus = hdw->ctl_read_urb->status;
-}
-
-
-int pvr2_hdw_gpio_get_dir(struct pvr2_hdw *hdw,u32 *dp)
-{
- return pvr2_read_register(hdw,PVR2_GPIO_DIR,dp);
-}
-
-
-int pvr2_hdw_gpio_get_out(struct pvr2_hdw *hdw,u32 *dp)
-{
- return pvr2_read_register(hdw,PVR2_GPIO_OUT,dp);
-}
-
-
-int pvr2_hdw_gpio_get_in(struct pvr2_hdw *hdw,u32 *dp)
-{
- return pvr2_read_register(hdw,PVR2_GPIO_IN,dp);
-}
-
-
-int pvr2_hdw_gpio_chg_dir(struct pvr2_hdw *hdw,u32 msk,u32 val)
-{
- u32 cval,nval;
- int ret;
- if (~msk) {
- ret = pvr2_read_register(hdw,PVR2_GPIO_DIR,&cval);
- if (ret) return ret;
- nval = (cval & ~msk) | (val & msk);
- pvr2_trace(PVR2_TRACE_GPIO,
- "GPIO direction changing 0x%x:0x%x"
- " from 0x%x to 0x%x",
- msk,val,cval,nval);
- } else {
- nval = val;
- pvr2_trace(PVR2_TRACE_GPIO,
- "GPIO direction changing to 0x%x",nval);
- }
- return pvr2_write_register(hdw,PVR2_GPIO_DIR,nval);
-}
-
-
-int pvr2_hdw_gpio_chg_out(struct pvr2_hdw *hdw,u32 msk,u32 val)
-{
- u32 cval,nval;
- int ret;
- if (~msk) {
- ret = pvr2_read_register(hdw,PVR2_GPIO_OUT,&cval);
- if (ret) return ret;
- nval = (cval & ~msk) | (val & msk);
- pvr2_trace(PVR2_TRACE_GPIO,
- "GPIO output changing 0x%x:0x%x from 0x%x to 0x%x",
- msk,val,cval,nval);
- } else {
- nval = val;
- pvr2_trace(PVR2_TRACE_GPIO,
- "GPIO output changing to 0x%x",nval);
- }
- return pvr2_write_register(hdw,PVR2_GPIO_OUT,nval);
-}
-
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 75 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */