[media] drx-j: get rid of drx_driver.c
This file contains just the firmware load code, that it is also somewhat duplicated at drxj.c. Move the code into there. Latter patches will remove the duplicated code. Acked-by: Devin Heitmueller <dheitmueller@kernellabs.com> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
This commit is contained in:
parent
ad55f6c881
commit
b240eacdd5
|
@ -1,4 +1,4 @@
|
|||
drx39xyj-objs := drx39xxj.o drx_driver.o drx39xxj_dummy.o drxj.o drx_dap_fasi.o
|
||||
drx39xyj-objs := drx39xxj.o drx39xxj_dummy.o drxj.o drx_dap_fasi.o
|
||||
|
||||
obj-$(CONFIG_DVB_DRX39XYJ) += drx39xyj.o
|
||||
|
||||
|
|
|
@ -1,651 +0,0 @@
|
|||
/*
|
||||
Generic DRX functionality, DRX driver core.
|
||||
|
||||
Copyright (c), 2004-2005,2007-2010 Trident Microsystems, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of Trident Microsystems nor Hauppauge Computer Works
|
||||
nor the names of its contributors may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
INCLUDE FILES
|
||||
------------------------------------------------------------------------------*/
|
||||
#include "drx_driver.h"
|
||||
|
||||
#define VERSION_MAJOR 0
|
||||
#define VERSION_MINOR 0
|
||||
#define VERSION_PATCH 0
|
||||
|
||||
/*
|
||||
* DEFINES
|
||||
*/
|
||||
|
||||
/*
|
||||
* MICROCODE RELATED DEFINES
|
||||
*/
|
||||
|
||||
/* Magic word for checking correct Endianess of microcode data */
|
||||
#define DRX_UCODE_MAGIC_WORD ((((u16)'H')<<8)+((u16)'L'))
|
||||
|
||||
/* CRC flag in ucode header, flags field. */
|
||||
#define DRX_UCODE_CRC_FLAG (0x0001)
|
||||
|
||||
/*
|
||||
* Maximum size of buffer used to verify the microcode.
|
||||
* Must be an even number
|
||||
*/
|
||||
#define DRX_UCODE_MAX_BUF_SIZE (DRXDAP_MAX_RCHUNKSIZE)
|
||||
|
||||
#if DRX_UCODE_MAX_BUF_SIZE & 1
|
||||
#error DRX_UCODE_MAX_BUF_SIZE must be an even number
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Power mode macros
|
||||
*/
|
||||
|
||||
#define DRX_ISPOWERDOWNMODE(mode) ((mode == DRX_POWER_MODE_9) || \
|
||||
(mode == DRX_POWER_MODE_10) || \
|
||||
(mode == DRX_POWER_MODE_11) || \
|
||||
(mode == DRX_POWER_MODE_12) || \
|
||||
(mode == DRX_POWER_MODE_13) || \
|
||||
(mode == DRX_POWER_MODE_14) || \
|
||||
(mode == DRX_POWER_MODE_15) || \
|
||||
(mode == DRX_POWER_MODE_16) || \
|
||||
(mode == DRX_POWER_DOWN))
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
STRUCTURES
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* struct drxu_code_block_hdr - Structure of the microcode block headers
|
||||
*
|
||||
* @addr: Destination address of the data in this block
|
||||
* @size: Size of the block data following this header counted in
|
||||
* 16 bits words
|
||||
* @CRC: CRC value of the data block, only valid if CRC flag is
|
||||
* set.
|
||||
*/
|
||||
struct drxu_code_block_hdr {
|
||||
u32 addr;
|
||||
u16 size;
|
||||
u16 flags;
|
||||
u16 CRC;
|
||||
};
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
FUNCTIONS
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Microcode related functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* drx_u_code_compute_crc - Compute CRC of block of microcode data.
|
||||
* @block_data: Pointer to microcode data.
|
||||
* @nr_words: Size of microcode block (number of 16 bits words).
|
||||
*
|
||||
* returns The computed CRC residue.
|
||||
*/
|
||||
static u16 drx_u_code_compute_crc(u8 *block_data, u16 nr_words)
|
||||
{
|
||||
u16 i = 0;
|
||||
u16 j = 0;
|
||||
u32 crc_word = 0;
|
||||
u32 carry = 0;
|
||||
|
||||
while (i < nr_words) {
|
||||
crc_word |= (u32)be16_to_cpu(*(u32 *)(block_data));
|
||||
for (j = 0; j < 16; j++) {
|
||||
crc_word <<= 1;
|
||||
if (carry != 0)
|
||||
crc_word ^= 0x80050000UL;
|
||||
carry = crc_word & 0x80000000UL;
|
||||
}
|
||||
i++;
|
||||
block_data += (sizeof(u16));
|
||||
}
|
||||
return (u16)(crc_word >> 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* drx_check_firmware - checks if the loaded firmware is valid
|
||||
*
|
||||
* @demod: demod structure
|
||||
* @mc_data: pointer to the start of the firmware
|
||||
* @size: firmware size
|
||||
*/
|
||||
static int drx_check_firmware(struct drx_demod_instance *demod, u8 *mc_data,
|
||||
unsigned size)
|
||||
{
|
||||
struct drxu_code_block_hdr block_hdr;
|
||||
int i;
|
||||
unsigned count = 2 * sizeof(u16);
|
||||
u32 mc_dev_type, mc_version, mc_base_version;
|
||||
u16 mc_nr_of_blks = be16_to_cpu(*(u32 *)(mc_data + sizeof(u16)));
|
||||
|
||||
/*
|
||||
* Scan microcode blocks first for version info
|
||||
* and firmware check
|
||||
*/
|
||||
|
||||
/* Clear version block */
|
||||
DRX_ATTR_MCRECORD(demod).aux_type = 0;
|
||||
DRX_ATTR_MCRECORD(demod).mc_dev_type = 0;
|
||||
DRX_ATTR_MCRECORD(demod).mc_version = 0;
|
||||
DRX_ATTR_MCRECORD(demod).mc_base_version = 0;
|
||||
|
||||
for (i = 0; i < mc_nr_of_blks; i++) {
|
||||
if (count + 3 * sizeof(u16) + sizeof(u32) > size)
|
||||
goto eof;
|
||||
|
||||
/* Process block header */
|
||||
block_hdr.addr = be32_to_cpu(*(u32 *)(mc_data + count));
|
||||
count += sizeof(u32);
|
||||
block_hdr.size = be16_to_cpu(*(u32 *)(mc_data + count));
|
||||
count += sizeof(u16);
|
||||
block_hdr.flags = be16_to_cpu(*(u32 *)(mc_data + count));
|
||||
count += sizeof(u16);
|
||||
block_hdr.CRC = be16_to_cpu(*(u32 *)(mc_data + count));
|
||||
count += sizeof(u16);
|
||||
|
||||
pr_debug("%u: addr %u, size %u, flags 0x%04x, CRC 0x%04x\n",
|
||||
count, block_hdr.addr, block_hdr.size, block_hdr.flags,
|
||||
block_hdr.CRC);
|
||||
|
||||
if (block_hdr.flags & 0x8) {
|
||||
u8 *auxblk = ((void *)mc_data) + block_hdr.addr;
|
||||
u16 auxtype;
|
||||
|
||||
if (block_hdr.addr + sizeof(u16) > size)
|
||||
goto eof;
|
||||
|
||||
auxtype = be16_to_cpu(*(u32 *)(auxblk));
|
||||
|
||||
/* Aux block. Check type */
|
||||
if (DRX_ISMCVERTYPE(auxtype)) {
|
||||
if (block_hdr.addr + 2 * sizeof(u16) + 2 * sizeof (u32) > size)
|
||||
goto eof;
|
||||
|
||||
auxblk += sizeof(u16);
|
||||
mc_dev_type = be32_to_cpu(*(u32 *)(auxblk));
|
||||
auxblk += sizeof(u32);
|
||||
mc_version = be32_to_cpu(*(u32 *)(auxblk));
|
||||
auxblk += sizeof(u32);
|
||||
mc_base_version = be32_to_cpu(*(u32 *)(auxblk));
|
||||
|
||||
DRX_ATTR_MCRECORD(demod).aux_type = auxtype;
|
||||
DRX_ATTR_MCRECORD(demod).mc_dev_type = mc_dev_type;
|
||||
DRX_ATTR_MCRECORD(demod).mc_version = mc_version;
|
||||
DRX_ATTR_MCRECORD(demod).mc_base_version = mc_base_version;
|
||||
|
||||
pr_info("Firmware dev %x, ver %x, base ver %x\n",
|
||||
mc_dev_type, mc_version, mc_base_version);
|
||||
|
||||
}
|
||||
} else if (count + block_hdr.size * sizeof(u16) > size)
|
||||
goto eof;
|
||||
|
||||
count += block_hdr.size * sizeof(u16);
|
||||
}
|
||||
return 0;
|
||||
eof:
|
||||
pr_err("Firmware is truncated at pos %u/%u\n", count, size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* drx_ctrl_u_code - Handle microcode upload or verify.
|
||||
* @dev_addr: Address of device.
|
||||
* @mc_info: Pointer to information about microcode data.
|
||||
* @action: Either UCODE_UPLOAD or UCODE_VERIFY
|
||||
*
|
||||
* This function returns:
|
||||
* 0:
|
||||
* - In case of UCODE_UPLOAD: code is successfully uploaded.
|
||||
* - In case of UCODE_VERIFY: image on device is equal to
|
||||
* image provided to this control function.
|
||||
* -EIO:
|
||||
* - In case of UCODE_UPLOAD: I2C error.
|
||||
* - In case of UCODE_VERIFY: I2C error or image on device
|
||||
* is not equal to image provided to this control function.
|
||||
* -EINVAL:
|
||||
* - Invalid arguments.
|
||||
* - Provided image is corrupt
|
||||
*/
|
||||
static int drx_ctrl_u_code(struct drx_demod_instance *demod,
|
||||
struct drxu_code_info *mc_info,
|
||||
enum drxu_code_action action)
|
||||
{
|
||||
struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr;
|
||||
int rc;
|
||||
u16 i = 0;
|
||||
u16 mc_nr_of_blks = 0;
|
||||
u16 mc_magic_word = 0;
|
||||
const u8 *mc_data_init = NULL;
|
||||
u8 *mc_data = NULL;
|
||||
unsigned size;
|
||||
char *mc_file = mc_info->mc_file;
|
||||
|
||||
/* Check arguments */
|
||||
if (!mc_info || !mc_file)
|
||||
return -EINVAL;
|
||||
|
||||
if (!demod->firmware) {
|
||||
const struct firmware *fw = NULL;
|
||||
|
||||
rc = request_firmware(&fw, mc_file, demod->i2c->dev.parent);
|
||||
if (rc < 0) {
|
||||
pr_err("Couldn't read firmware %s\n", mc_file);
|
||||
return -ENOENT;
|
||||
}
|
||||
demod->firmware = fw;
|
||||
|
||||
if (demod->firmware->size < 2 * sizeof(u16)) {
|
||||
rc = -EINVAL;
|
||||
pr_err("Firmware is too short!\n");
|
||||
goto release;
|
||||
}
|
||||
|
||||
pr_info("Firmware %s, size %zu\n",
|
||||
mc_file, demod->firmware->size);
|
||||
}
|
||||
|
||||
mc_data_init = demod->firmware->data;
|
||||
size = demod->firmware->size;
|
||||
|
||||
mc_data = (void *)mc_data_init;
|
||||
/* Check data */
|
||||
mc_magic_word = be16_to_cpu(*(u32 *)(mc_data));
|
||||
mc_data += sizeof(u16);
|
||||
mc_nr_of_blks = be16_to_cpu(*(u32 *)(mc_data));
|
||||
mc_data += sizeof(u16);
|
||||
|
||||
if ((mc_magic_word != DRX_UCODE_MAGIC_WORD) || (mc_nr_of_blks == 0)) {
|
||||
rc = -EINVAL;
|
||||
pr_err("Firmware magic word doesn't match\n");
|
||||
goto release;
|
||||
}
|
||||
|
||||
if (action == UCODE_UPLOAD) {
|
||||
rc = drx_check_firmware(demod, (u8 *)mc_data_init, size);
|
||||
if (rc)
|
||||
goto release;
|
||||
|
||||
/* After scanning, validate the microcode.
|
||||
It is also valid if no validation control exists.
|
||||
*/
|
||||
rc = drx_ctrl(demod, DRX_CTRL_VALIDATE_UCODE, NULL);
|
||||
if (rc != 0 && rc != -ENOTSUPP) {
|
||||
pr_err("Validate ucode not supported\n");
|
||||
return rc;
|
||||
}
|
||||
pr_info("Uploading firmware %s\n", mc_file);
|
||||
} else if (action == UCODE_VERIFY) {
|
||||
pr_info("Verifying if firmware upload was ok.\n");
|
||||
}
|
||||
|
||||
/* Process microcode blocks */
|
||||
for (i = 0; i < mc_nr_of_blks; i++) {
|
||||
struct drxu_code_block_hdr block_hdr;
|
||||
u16 mc_block_nr_bytes = 0;
|
||||
|
||||
/* Process block header */
|
||||
block_hdr.addr = be32_to_cpu(*(u32 *)(mc_data));
|
||||
mc_data += sizeof(u32);
|
||||
block_hdr.size = be16_to_cpu(*(u32 *)(mc_data));
|
||||
mc_data += sizeof(u16);
|
||||
block_hdr.flags = be16_to_cpu(*(u32 *)(mc_data));
|
||||
mc_data += sizeof(u16);
|
||||
block_hdr.CRC = be16_to_cpu(*(u32 *)(mc_data));
|
||||
mc_data += sizeof(u16);
|
||||
|
||||
pr_debug("%u: addr %u, size %u, flags 0x%04x, CRC 0x%04x\n",
|
||||
(unsigned)(mc_data - mc_data_init), block_hdr.addr,
|
||||
block_hdr.size, block_hdr.flags, block_hdr.CRC);
|
||||
|
||||
/* Check block header on:
|
||||
- data larger than 64Kb
|
||||
- if CRC enabled check CRC
|
||||
*/
|
||||
if ((block_hdr.size > 0x7FFF) ||
|
||||
(((block_hdr.flags & DRX_UCODE_CRC_FLAG) != 0) &&
|
||||
(block_hdr.CRC != drx_u_code_compute_crc(mc_data, block_hdr.size)))
|
||||
) {
|
||||
/* Wrong data ! */
|
||||
rc = -EINVAL;
|
||||
pr_err("firmware CRC is wrong\n");
|
||||
goto release;
|
||||
}
|
||||
|
||||
if (!block_hdr.size)
|
||||
continue;
|
||||
|
||||
mc_block_nr_bytes = block_hdr.size * ((u16) sizeof(u16));
|
||||
|
||||
/* Perform the desired action */
|
||||
switch (action) {
|
||||
case UCODE_UPLOAD: /* Upload microcode */
|
||||
if (demod->my_access_funct->write_block_func(dev_addr,
|
||||
block_hdr.addr,
|
||||
mc_block_nr_bytes,
|
||||
mc_data, 0x0000)) {
|
||||
rc = -EIO;
|
||||
pr_err("error writing firmware at pos %u\n",
|
||||
(unsigned)(mc_data - mc_data_init));
|
||||
goto release;
|
||||
}
|
||||
break;
|
||||
case UCODE_VERIFY: { /* Verify uploaded microcode */
|
||||
int result = 0;
|
||||
u8 mc_data_buffer[DRX_UCODE_MAX_BUF_SIZE];
|
||||
u32 bytes_to_comp = 0;
|
||||
u32 bytes_left = mc_block_nr_bytes;
|
||||
u32 curr_addr = block_hdr.addr;
|
||||
u8 *curr_ptr = mc_data;
|
||||
|
||||
while (bytes_left != 0) {
|
||||
if (bytes_left > DRX_UCODE_MAX_BUF_SIZE)
|
||||
bytes_to_comp = DRX_UCODE_MAX_BUF_SIZE;
|
||||
else
|
||||
bytes_to_comp = bytes_left;
|
||||
|
||||
if (demod->my_access_funct->
|
||||
read_block_func(dev_addr,
|
||||
curr_addr,
|
||||
(u16)bytes_to_comp,
|
||||
(u8 *)mc_data_buffer,
|
||||
0x0000)) {
|
||||
pr_err("error reading firmware at pos %u\n",
|
||||
(unsigned)(mc_data - mc_data_init));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
result =drxbsp_hst_memcmp(curr_ptr,
|
||||
mc_data_buffer,
|
||||
bytes_to_comp);
|
||||
|
||||
if (result) {
|
||||
pr_err("error verifying firmware at pos %u\n",
|
||||
(unsigned)(mc_data - mc_data_init));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
curr_addr += ((dr_xaddr_t)(bytes_to_comp / 2));
|
||||
curr_ptr =&(curr_ptr[bytes_to_comp]);
|
||||
bytes_left -=((u32) bytes_to_comp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
break;
|
||||
|
||||
}
|
||||
mc_data += mc_block_nr_bytes;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
release:
|
||||
release_firmware(demod->firmware);
|
||||
demod->firmware = NULL;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*============================================================================*/
|
||||
|
||||
/**
|
||||
* drx_ctrl_version - Build list of version information.
|
||||
* @demod: A pointer to a demodulator instance.
|
||||
* @version_list: Pointer to linked list of versions.
|
||||
*
|
||||
* This function returns:
|
||||
* 0: Version information stored in version_list
|
||||
* -EINVAL: Invalid arguments.
|
||||
*/
|
||||
static int drx_ctrl_version(struct drx_demod_instance *demod,
|
||||
struct drx_version_list **version_list)
|
||||
{
|
||||
static char drx_driver_core_module_name[] = "Core driver";
|
||||
static char drx_driver_core_version_text[] =
|
||||
DRX_VERSIONSTRING(VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH);
|
||||
|
||||
static struct drx_version drx_driver_core_version;
|
||||
static struct drx_version_list drx_driver_core_version_list;
|
||||
|
||||
struct drx_version_list *demod_version_list = NULL;
|
||||
int return_status = -EIO;
|
||||
|
||||
/* Check arguments */
|
||||
if (version_list == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
/* Get version info list from demod */
|
||||
return_status = (*(demod->my_demod_funct->ctrl_func)) (demod,
|
||||
DRX_CTRL_VERSION,
|
||||
(void *)
|
||||
&demod_version_list);
|
||||
|
||||
/* Always fill in the information of the driver SW . */
|
||||
drx_driver_core_version.module_type = DRX_MODULE_DRIVERCORE;
|
||||
drx_driver_core_version.module_name = drx_driver_core_module_name;
|
||||
drx_driver_core_version.v_major = VERSION_MAJOR;
|
||||
drx_driver_core_version.v_minor = VERSION_MINOR;
|
||||
drx_driver_core_version.v_patch = VERSION_PATCH;
|
||||
drx_driver_core_version.v_string = drx_driver_core_version_text;
|
||||
|
||||
drx_driver_core_version_list.version = &drx_driver_core_version;
|
||||
drx_driver_core_version_list.next = (struct drx_version_list *) (NULL);
|
||||
|
||||
if ((return_status == 0) && (demod_version_list != NULL)) {
|
||||
/* Append versioninfo from driver to versioninfo from demod */
|
||||
/* Return version info in "bottom-up" order. This way, multiple
|
||||
devices can be handled without using malloc. */
|
||||
struct drx_version_list *current_list_element = demod_version_list;
|
||||
while (current_list_element->next != NULL)
|
||||
current_list_element = current_list_element->next;
|
||||
current_list_element->next = &drx_driver_core_version_list;
|
||||
|
||||
*version_list = demod_version_list;
|
||||
} else {
|
||||
/* Just return versioninfo from driver */
|
||||
*version_list = &drx_driver_core_version_list;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Exported functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* drx_open - Open a demodulator instance.
|
||||
* @demod: A pointer to a demodulator instance.
|
||||
*
|
||||
* This function returns:
|
||||
* 0: Opened demod instance with succes.
|
||||
* -EIO: Driver not initialized or unable to initialize
|
||||
* demod.
|
||||
* -EINVAL: Demod instance has invalid content.
|
||||
*
|
||||
*/
|
||||
|
||||
int drx_open(struct drx_demod_instance *demod)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
if ((demod == NULL) ||
|
||||
(demod->my_demod_funct == NULL) ||
|
||||
(demod->my_common_attr == NULL) ||
|
||||
(demod->my_ext_attr == NULL) ||
|
||||
(demod->my_i2c_dev_addr == NULL) ||
|
||||
(demod->my_common_attr->is_opened)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
status = (*(demod->my_demod_funct->open_func)) (demod);
|
||||
|
||||
if (status == 0)
|
||||
demod->my_common_attr->is_opened = true;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*============================================================================*/
|
||||
|
||||
/**
|
||||
* drx_close - Close device
|
||||
* @demod: A pointer to a demodulator instance.
|
||||
*
|
||||
* Free resources occupied by device instance.
|
||||
* Put device into sleep mode.
|
||||
*
|
||||
* This function returns:
|
||||
* 0: Closed demod instance with succes.
|
||||
* -EIO: Driver not initialized or error during close
|
||||
* demod.
|
||||
* -EINVAL: Demod instance has invalid content.
|
||||
*/
|
||||
int drx_close(struct drx_demod_instance *demod)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
if ((demod == NULL) ||
|
||||
(demod->my_demod_funct == NULL) ||
|
||||
(demod->my_common_attr == NULL) ||
|
||||
(demod->my_ext_attr == NULL) ||
|
||||
(demod->my_i2c_dev_addr == NULL) ||
|
||||
(!demod->my_common_attr->is_opened)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
status = (*(demod->my_demod_funct->close_func)) (demod);
|
||||
|
||||
DRX_ATTR_ISOPENED(demod) = false;
|
||||
|
||||
return status;
|
||||
}
|
||||
/**
|
||||
* drx_ctrl - Control the device.
|
||||
* @demod: A pointer to a demodulator instance.
|
||||
* @ctrl: Reference to desired control function.
|
||||
* @ctrl_data: Pointer to data structure for control function.
|
||||
*
|
||||
* Data needed or returned by the control function is stored in ctrl_data.
|
||||
*
|
||||
* This function returns:
|
||||
* 0: Control function completed successfully.
|
||||
* -EIO: Driver not initialized or error during control demod.
|
||||
* -EINVAL: Demod instance or ctrl_data has invalid content.
|
||||
* -ENOTSUPP: Specified control function is not available.
|
||||
*/
|
||||
|
||||
int drx_ctrl(struct drx_demod_instance *demod, u32 ctrl, void *ctrl_data)
|
||||
{
|
||||
int status = -EIO;
|
||||
|
||||
if ((demod == NULL) ||
|
||||
(demod->my_demod_funct == NULL) ||
|
||||
(demod->my_common_attr == NULL) ||
|
||||
(demod->my_ext_attr == NULL) || (demod->my_i2c_dev_addr == NULL)
|
||||
) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (((!demod->my_common_attr->is_opened) &&
|
||||
(ctrl != DRX_CTRL_PROBE_DEVICE) && (ctrl != DRX_CTRL_VERSION))
|
||||
) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((DRX_ISPOWERDOWNMODE(demod->my_common_attr->current_power_mode) &&
|
||||
(ctrl != DRX_CTRL_POWER_MODE) &&
|
||||
(ctrl != DRX_CTRL_PROBE_DEVICE) &&
|
||||
(ctrl != DRX_CTRL_NOP) && (ctrl != DRX_CTRL_VERSION)
|
||||
)
|
||||
) {
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
/* Fixed control functions */
|
||||
switch (ctrl) {
|
||||
/*======================================================================*/
|
||||
case DRX_CTRL_NOP:
|
||||
/* No operation */
|
||||
return 0;
|
||||
break;
|
||||
|
||||
/*======================================================================*/
|
||||
case DRX_CTRL_VERSION:
|
||||
return drx_ctrl_version(demod, (struct drx_version_list **)ctrl_data);
|
||||
break;
|
||||
|
||||
/*======================================================================*/
|
||||
default:
|
||||
/* Do nothing */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Virtual functions */
|
||||
/* First try calling function from derived class */
|
||||
status = (*(demod->my_demod_funct->ctrl_func)) (demod, ctrl, ctrl_data);
|
||||
if (status == -ENOTSUPP) {
|
||||
/* Now try calling a the base class function */
|
||||
switch (ctrl) {
|
||||
/*===================================================================*/
|
||||
case DRX_CTRL_LOAD_UCODE:
|
||||
return drx_ctrl_u_code(demod,
|
||||
(struct drxu_code_info *)ctrl_data,
|
||||
UCODE_UPLOAD);
|
||||
break;
|
||||
|
||||
/*===================================================================*/
|
||||
case DRX_CTRL_VERIFY_UCODE:
|
||||
{
|
||||
return drx_ctrl_u_code(demod,
|
||||
(struct drxu_code_info *)ctrl_data,
|
||||
UCODE_VERIFY);
|
||||
}
|
||||
break;
|
||||
|
||||
/*===================================================================*/
|
||||
default:
|
||||
pr_err("control %d not supported\n", ctrl);
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
} else {
|
||||
return status;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -39,6 +39,7 @@ INCLUDE FILES
|
|||
|
||||
#include "drxj.h"
|
||||
#include "drxj_map.h"
|
||||
#include "drx_driver.h"
|
||||
|
||||
/*============================================================================*/
|
||||
/*=== DEFINES ================================================================*/
|
||||
|
@ -309,6 +310,40 @@ DEFINES
|
|||
#define DRX_UIO_MODE_FIRMWARE_SMA DRX_UIO_MODE_FIRMWARE0
|
||||
#define DRX_UIO_MODE_FIRMWARE_SAW DRX_UIO_MODE_FIRMWARE1
|
||||
|
||||
/*
|
||||
* MICROCODE RELATED DEFINES
|
||||
*/
|
||||
|
||||
/* Magic word for checking correct Endianess of microcode data */
|
||||
#define DRX_UCODE_MAGIC_WORD ((((u16)'H')<<8)+((u16)'L'))
|
||||
|
||||
/* CRC flag in ucode header, flags field. */
|
||||
#define DRX_UCODE_CRC_FLAG (0x0001)
|
||||
|
||||
/*
|
||||
* Maximum size of buffer used to verify the microcode.
|
||||
* Must be an even number
|
||||
*/
|
||||
#define DRX_UCODE_MAX_BUF_SIZE (DRXDAP_MAX_RCHUNKSIZE)
|
||||
|
||||
#if DRX_UCODE_MAX_BUF_SIZE & 1
|
||||
#error DRX_UCODE_MAX_BUF_SIZE must be an even number
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Power mode macros
|
||||
*/
|
||||
|
||||
#define DRX_ISPOWERDOWNMODE(mode) ((mode == DRX_POWER_MODE_9) || \
|
||||
(mode == DRX_POWER_MODE_10) || \
|
||||
(mode == DRX_POWER_MODE_11) || \
|
||||
(mode == DRX_POWER_MODE_12) || \
|
||||
(mode == DRX_POWER_MODE_13) || \
|
||||
(mode == DRX_POWER_MODE_14) || \
|
||||
(mode == DRX_POWER_MODE_15) || \
|
||||
(mode == DRX_POWER_MODE_16) || \
|
||||
(mode == DRX_POWER_DOWN))
|
||||
|
||||
#ifdef DRXJ_SPLIT_UCODE_UPLOAD
|
||||
/*============================================================================*/
|
||||
/*=== MICROCODE RELATED DEFINES ==============================================*/
|
||||
|
@ -1050,20 +1085,25 @@ struct drxj_hi_cmd {
|
|||
u16 param6;
|
||||
};
|
||||
|
||||
#ifdef DRXJ_SPLIT_UCODE_UPLOAD
|
||||
/*============================================================================*/
|
||||
/*=== MICROCODE RELATED STRUCTURES ===========================================*/
|
||||
/*============================================================================*/
|
||||
|
||||
/**
|
||||
* struct drxu_code_block_hdr - Structure of the microcode block headers
|
||||
*
|
||||
* @addr: Destination address of the data in this block
|
||||
* @size: Size of the block data following this header counted in
|
||||
* 16 bits words
|
||||
* @CRC: CRC value of the data block, only valid if CRC flag is
|
||||
* set.
|
||||
*/
|
||||
struct drxu_code_block_hdr {
|
||||
u32 addr;
|
||||
u16 size;
|
||||
u16 flags; /* bit[15..2]=reserved,
|
||||
bit[1]= compression on/off
|
||||
bit[0]= CRC on/off */
|
||||
u16 flags;
|
||||
u16 CRC;
|
||||
};
|
||||
#endif /* DRXJ_SPLIT_UCODE_UPLOAD */
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
FUNCTIONS
|
||||
|
@ -20607,3 +20647,550 @@ drxj_ctrl(struct drx_demod_instance *demod, u32 ctrl, void *ctrl_data)
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Microcode related functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* drx_u_code_compute_crc - Compute CRC of block of microcode data.
|
||||
* @block_data: Pointer to microcode data.
|
||||
* @nr_words: Size of microcode block (number of 16 bits words).
|
||||
*
|
||||
* returns The computed CRC residue.
|
||||
*/
|
||||
static u16 drx_u_code_compute_crc(u8 *block_data, u16 nr_words)
|
||||
{
|
||||
u16 i = 0;
|
||||
u16 j = 0;
|
||||
u32 crc_word = 0;
|
||||
u32 carry = 0;
|
||||
|
||||
while (i < nr_words) {
|
||||
crc_word |= (u32)be16_to_cpu(*(u32 *)(block_data));
|
||||
for (j = 0; j < 16; j++) {
|
||||
crc_word <<= 1;
|
||||
if (carry != 0)
|
||||
crc_word ^= 0x80050000UL;
|
||||
carry = crc_word & 0x80000000UL;
|
||||
}
|
||||
i++;
|
||||
block_data += (sizeof(u16));
|
||||
}
|
||||
return (u16)(crc_word >> 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* drx_check_firmware - checks if the loaded firmware is valid
|
||||
*
|
||||
* @demod: demod structure
|
||||
* @mc_data: pointer to the start of the firmware
|
||||
* @size: firmware size
|
||||
*/
|
||||
static int drx_check_firmware(struct drx_demod_instance *demod, u8 *mc_data,
|
||||
unsigned size)
|
||||
{
|
||||
struct drxu_code_block_hdr block_hdr;
|
||||
int i;
|
||||
unsigned count = 2 * sizeof(u16);
|
||||
u32 mc_dev_type, mc_version, mc_base_version;
|
||||
u16 mc_nr_of_blks = be16_to_cpu(*(u32 *)(mc_data + sizeof(u16)));
|
||||
|
||||
/*
|
||||
* Scan microcode blocks first for version info
|
||||
* and firmware check
|
||||
*/
|
||||
|
||||
/* Clear version block */
|
||||
DRX_ATTR_MCRECORD(demod).aux_type = 0;
|
||||
DRX_ATTR_MCRECORD(demod).mc_dev_type = 0;
|
||||
DRX_ATTR_MCRECORD(demod).mc_version = 0;
|
||||
DRX_ATTR_MCRECORD(demod).mc_base_version = 0;
|
||||
|
||||
for (i = 0; i < mc_nr_of_blks; i++) {
|
||||
if (count + 3 * sizeof(u16) + sizeof(u32) > size)
|
||||
goto eof;
|
||||
|
||||
/* Process block header */
|
||||
block_hdr.addr = be32_to_cpu(*(u32 *)(mc_data + count));
|
||||
count += sizeof(u32);
|
||||
block_hdr.size = be16_to_cpu(*(u32 *)(mc_data + count));
|
||||
count += sizeof(u16);
|
||||
block_hdr.flags = be16_to_cpu(*(u32 *)(mc_data + count));
|
||||
count += sizeof(u16);
|
||||
block_hdr.CRC = be16_to_cpu(*(u32 *)(mc_data + count));
|
||||
count += sizeof(u16);
|
||||
|
||||
pr_debug("%u: addr %u, size %u, flags 0x%04x, CRC 0x%04x\n",
|
||||
count, block_hdr.addr, block_hdr.size, block_hdr.flags,
|
||||
block_hdr.CRC);
|
||||
|
||||
if (block_hdr.flags & 0x8) {
|
||||
u8 *auxblk = ((void *)mc_data) + block_hdr.addr;
|
||||
u16 auxtype;
|
||||
|
||||
if (block_hdr.addr + sizeof(u16) > size)
|
||||
goto eof;
|
||||
|
||||
auxtype = be16_to_cpu(*(u32 *)(auxblk));
|
||||
|
||||
/* Aux block. Check type */
|
||||
if (DRX_ISMCVERTYPE(auxtype)) {
|
||||
if (block_hdr.addr + 2 * sizeof(u16) + 2 * sizeof (u32) > size)
|
||||
goto eof;
|
||||
|
||||
auxblk += sizeof(u16);
|
||||
mc_dev_type = be32_to_cpu(*(u32 *)(auxblk));
|
||||
auxblk += sizeof(u32);
|
||||
mc_version = be32_to_cpu(*(u32 *)(auxblk));
|
||||
auxblk += sizeof(u32);
|
||||
mc_base_version = be32_to_cpu(*(u32 *)(auxblk));
|
||||
|
||||
DRX_ATTR_MCRECORD(demod).aux_type = auxtype;
|
||||
DRX_ATTR_MCRECORD(demod).mc_dev_type = mc_dev_type;
|
||||
DRX_ATTR_MCRECORD(demod).mc_version = mc_version;
|
||||
DRX_ATTR_MCRECORD(demod).mc_base_version = mc_base_version;
|
||||
|
||||
pr_info("Firmware dev %x, ver %x, base ver %x\n",
|
||||
mc_dev_type, mc_version, mc_base_version);
|
||||
|
||||
}
|
||||
} else if (count + block_hdr.size * sizeof(u16) > size)
|
||||
goto eof;
|
||||
|
||||
count += block_hdr.size * sizeof(u16);
|
||||
}
|
||||
return 0;
|
||||
eof:
|
||||
pr_err("Firmware is truncated at pos %u/%u\n", count, size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* drx_ctrl_u_code - Handle microcode upload or verify.
|
||||
* @dev_addr: Address of device.
|
||||
* @mc_info: Pointer to information about microcode data.
|
||||
* @action: Either UCODE_UPLOAD or UCODE_VERIFY
|
||||
*
|
||||
* This function returns:
|
||||
* 0:
|
||||
* - In case of UCODE_UPLOAD: code is successfully uploaded.
|
||||
* - In case of UCODE_VERIFY: image on device is equal to
|
||||
* image provided to this control function.
|
||||
* -EIO:
|
||||
* - In case of UCODE_UPLOAD: I2C error.
|
||||
* - In case of UCODE_VERIFY: I2C error or image on device
|
||||
* is not equal to image provided to this control function.
|
||||
* -EINVAL:
|
||||
* - Invalid arguments.
|
||||
* - Provided image is corrupt
|
||||
*/
|
||||
static int drx_ctrl_u_code(struct drx_demod_instance *demod,
|
||||
struct drxu_code_info *mc_info,
|
||||
enum drxu_code_action action)
|
||||
{
|
||||
struct i2c_device_addr *dev_addr = demod->my_i2c_dev_addr;
|
||||
int rc;
|
||||
u16 i = 0;
|
||||
u16 mc_nr_of_blks = 0;
|
||||
u16 mc_magic_word = 0;
|
||||
const u8 *mc_data_init = NULL;
|
||||
u8 *mc_data = NULL;
|
||||
unsigned size;
|
||||
char *mc_file = mc_info->mc_file;
|
||||
|
||||
/* Check arguments */
|
||||
if (!mc_info || !mc_file)
|
||||
return -EINVAL;
|
||||
|
||||
if (!demod->firmware) {
|
||||
const struct firmware *fw = NULL;
|
||||
|
||||
rc = request_firmware(&fw, mc_file, demod->i2c->dev.parent);
|
||||
if (rc < 0) {
|
||||
pr_err("Couldn't read firmware %s\n", mc_file);
|
||||
return -ENOENT;
|
||||
}
|
||||
demod->firmware = fw;
|
||||
|
||||
if (demod->firmware->size < 2 * sizeof(u16)) {
|
||||
rc = -EINVAL;
|
||||
pr_err("Firmware is too short!\n");
|
||||
goto release;
|
||||
}
|
||||
|
||||
pr_info("Firmware %s, size %zu\n",
|
||||
mc_file, demod->firmware->size);
|
||||
}
|
||||
|
||||
mc_data_init = demod->firmware->data;
|
||||
size = demod->firmware->size;
|
||||
|
||||
mc_data = (void *)mc_data_init;
|
||||
/* Check data */
|
||||
mc_magic_word = be16_to_cpu(*(u32 *)(mc_data));
|
||||
mc_data += sizeof(u16);
|
||||
mc_nr_of_blks = be16_to_cpu(*(u32 *)(mc_data));
|
||||
mc_data += sizeof(u16);
|
||||
|
||||
if ((mc_magic_word != DRX_UCODE_MAGIC_WORD) || (mc_nr_of_blks == 0)) {
|
||||
rc = -EINVAL;
|
||||
pr_err("Firmware magic word doesn't match\n");
|
||||
goto release;
|
||||
}
|
||||
|
||||
if (action == UCODE_UPLOAD) {
|
||||
rc = drx_check_firmware(demod, (u8 *)mc_data_init, size);
|
||||
if (rc)
|
||||
goto release;
|
||||
|
||||
/* After scanning, validate the microcode.
|
||||
It is also valid if no validation control exists.
|
||||
*/
|
||||
rc = drx_ctrl(demod, DRX_CTRL_VALIDATE_UCODE, NULL);
|
||||
if (rc != 0 && rc != -ENOTSUPP) {
|
||||
pr_err("Validate ucode not supported\n");
|
||||
return rc;
|
||||
}
|
||||
pr_info("Uploading firmware %s\n", mc_file);
|
||||
} else if (action == UCODE_VERIFY) {
|
||||
pr_info("Verifying if firmware upload was ok.\n");
|
||||
}
|
||||
|
||||
/* Process microcode blocks */
|
||||
for (i = 0; i < mc_nr_of_blks; i++) {
|
||||
struct drxu_code_block_hdr block_hdr;
|
||||
u16 mc_block_nr_bytes = 0;
|
||||
|
||||
/* Process block header */
|
||||
block_hdr.addr = be32_to_cpu(*(u32 *)(mc_data));
|
||||
mc_data += sizeof(u32);
|
||||
block_hdr.size = be16_to_cpu(*(u32 *)(mc_data));
|
||||
mc_data += sizeof(u16);
|
||||
block_hdr.flags = be16_to_cpu(*(u32 *)(mc_data));
|
||||
mc_data += sizeof(u16);
|
||||
block_hdr.CRC = be16_to_cpu(*(u32 *)(mc_data));
|
||||
mc_data += sizeof(u16);
|
||||
|
||||
pr_debug("%u: addr %u, size %u, flags 0x%04x, CRC 0x%04x\n",
|
||||
(unsigned)(mc_data - mc_data_init), block_hdr.addr,
|
||||
block_hdr.size, block_hdr.flags, block_hdr.CRC);
|
||||
|
||||
/* Check block header on:
|
||||
- data larger than 64Kb
|
||||
- if CRC enabled check CRC
|
||||
*/
|
||||
if ((block_hdr.size > 0x7FFF) ||
|
||||
(((block_hdr.flags & DRX_UCODE_CRC_FLAG) != 0) &&
|
||||
(block_hdr.CRC != drx_u_code_compute_crc(mc_data, block_hdr.size)))
|
||||
) {
|
||||
/* Wrong data ! */
|
||||
rc = -EINVAL;
|
||||
pr_err("firmware CRC is wrong\n");
|
||||
goto release;
|
||||
}
|
||||
|
||||
if (!block_hdr.size)
|
||||
continue;
|
||||
|
||||
mc_block_nr_bytes = block_hdr.size * ((u16) sizeof(u16));
|
||||
|
||||
/* Perform the desired action */
|
||||
switch (action) {
|
||||
case UCODE_UPLOAD: /* Upload microcode */
|
||||
if (demod->my_access_funct->write_block_func(dev_addr,
|
||||
block_hdr.addr,
|
||||
mc_block_nr_bytes,
|
||||
mc_data, 0x0000)) {
|
||||
rc = -EIO;
|
||||
pr_err("error writing firmware at pos %u\n",
|
||||
(unsigned)(mc_data - mc_data_init));
|
||||
goto release;
|
||||
}
|
||||
break;
|
||||
case UCODE_VERIFY: { /* Verify uploaded microcode */
|
||||
int result = 0;
|
||||
u8 mc_data_buffer[DRX_UCODE_MAX_BUF_SIZE];
|
||||
u32 bytes_to_comp = 0;
|
||||
u32 bytes_left = mc_block_nr_bytes;
|
||||
u32 curr_addr = block_hdr.addr;
|
||||
u8 *curr_ptr = mc_data;
|
||||
|
||||
while (bytes_left != 0) {
|
||||
if (bytes_left > DRX_UCODE_MAX_BUF_SIZE)
|
||||
bytes_to_comp = DRX_UCODE_MAX_BUF_SIZE;
|
||||
else
|
||||
bytes_to_comp = bytes_left;
|
||||
|
||||
if (demod->my_access_funct->
|
||||
read_block_func(dev_addr,
|
||||
curr_addr,
|
||||
(u16)bytes_to_comp,
|
||||
(u8 *)mc_data_buffer,
|
||||
0x0000)) {
|
||||
pr_err("error reading firmware at pos %u\n",
|
||||
(unsigned)(mc_data - mc_data_init));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
result =drxbsp_hst_memcmp(curr_ptr,
|
||||
mc_data_buffer,
|
||||
bytes_to_comp);
|
||||
|
||||
if (result) {
|
||||
pr_err("error verifying firmware at pos %u\n",
|
||||
(unsigned)(mc_data - mc_data_init));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
curr_addr += ((dr_xaddr_t)(bytes_to_comp / 2));
|
||||
curr_ptr =&(curr_ptr[bytes_to_comp]);
|
||||
bytes_left -=((u32) bytes_to_comp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
break;
|
||||
|
||||
}
|
||||
mc_data += mc_block_nr_bytes;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
release:
|
||||
release_firmware(demod->firmware);
|
||||
demod->firmware = NULL;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*============================================================================*/
|
||||
|
||||
/**
|
||||
* drx_ctrl_version - Build list of version information.
|
||||
* @demod: A pointer to a demodulator instance.
|
||||
* @version_list: Pointer to linked list of versions.
|
||||
*
|
||||
* This function returns:
|
||||
* 0: Version information stored in version_list
|
||||
* -EINVAL: Invalid arguments.
|
||||
*/
|
||||
static int drx_ctrl_version(struct drx_demod_instance *demod,
|
||||
struct drx_version_list **version_list)
|
||||
{
|
||||
static char drx_driver_core_module_name[] = "Core driver";
|
||||
static char drx_driver_core_version_text[] =
|
||||
DRX_VERSIONSTRING(VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH);
|
||||
|
||||
static struct drx_version drx_driver_core_version;
|
||||
static struct drx_version_list drx_driver_core_version_list;
|
||||
|
||||
struct drx_version_list *demod_version_list = NULL;
|
||||
int return_status = -EIO;
|
||||
|
||||
/* Check arguments */
|
||||
if (version_list == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
/* Get version info list from demod */
|
||||
return_status = (*(demod->my_demod_funct->ctrl_func)) (demod,
|
||||
DRX_CTRL_VERSION,
|
||||
(void *)
|
||||
&demod_version_list);
|
||||
|
||||
/* Always fill in the information of the driver SW . */
|
||||
drx_driver_core_version.module_type = DRX_MODULE_DRIVERCORE;
|
||||
drx_driver_core_version.module_name = drx_driver_core_module_name;
|
||||
drx_driver_core_version.v_major = VERSION_MAJOR;
|
||||
drx_driver_core_version.v_minor = VERSION_MINOR;
|
||||
drx_driver_core_version.v_patch = VERSION_PATCH;
|
||||
drx_driver_core_version.v_string = drx_driver_core_version_text;
|
||||
|
||||
drx_driver_core_version_list.version = &drx_driver_core_version;
|
||||
drx_driver_core_version_list.next = (struct drx_version_list *) (NULL);
|
||||
|
||||
if ((return_status == 0) && (demod_version_list != NULL)) {
|
||||
/* Append versioninfo from driver to versioninfo from demod */
|
||||
/* Return version info in "bottom-up" order. This way, multiple
|
||||
devices can be handled without using malloc. */
|
||||
struct drx_version_list *current_list_element = demod_version_list;
|
||||
while (current_list_element->next != NULL)
|
||||
current_list_element = current_list_element->next;
|
||||
current_list_element->next = &drx_driver_core_version_list;
|
||||
|
||||
*version_list = demod_version_list;
|
||||
} else {
|
||||
/* Just return versioninfo from driver */
|
||||
*version_list = &drx_driver_core_version_list;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Exported functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* drx_open - Open a demodulator instance.
|
||||
* @demod: A pointer to a demodulator instance.
|
||||
*
|
||||
* This function returns:
|
||||
* 0: Opened demod instance with succes.
|
||||
* -EIO: Driver not initialized or unable to initialize
|
||||
* demod.
|
||||
* -EINVAL: Demod instance has invalid content.
|
||||
*
|
||||
*/
|
||||
|
||||
int drx_open(struct drx_demod_instance *demod)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
if ((demod == NULL) ||
|
||||
(demod->my_demod_funct == NULL) ||
|
||||
(demod->my_common_attr == NULL) ||
|
||||
(demod->my_ext_attr == NULL) ||
|
||||
(demod->my_i2c_dev_addr == NULL) ||
|
||||
(demod->my_common_attr->is_opened)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
status = (*(demod->my_demod_funct->open_func)) (demod);
|
||||
|
||||
if (status == 0)
|
||||
demod->my_common_attr->is_opened = true;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*============================================================================*/
|
||||
|
||||
/**
|
||||
* drx_close - Close device
|
||||
* @demod: A pointer to a demodulator instance.
|
||||
*
|
||||
* Free resources occupied by device instance.
|
||||
* Put device into sleep mode.
|
||||
*
|
||||
* This function returns:
|
||||
* 0: Closed demod instance with succes.
|
||||
* -EIO: Driver not initialized or error during close
|
||||
* demod.
|
||||
* -EINVAL: Demod instance has invalid content.
|
||||
*/
|
||||
int drx_close(struct drx_demod_instance *demod)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
if ((demod == NULL) ||
|
||||
(demod->my_demod_funct == NULL) ||
|
||||
(demod->my_common_attr == NULL) ||
|
||||
(demod->my_ext_attr == NULL) ||
|
||||
(demod->my_i2c_dev_addr == NULL) ||
|
||||
(!demod->my_common_attr->is_opened)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
status = (*(demod->my_demod_funct->close_func)) (demod);
|
||||
|
||||
DRX_ATTR_ISOPENED(demod) = false;
|
||||
|
||||
return status;
|
||||
}
|
||||
/**
|
||||
* drx_ctrl - Control the device.
|
||||
* @demod: A pointer to a demodulator instance.
|
||||
* @ctrl: Reference to desired control function.
|
||||
* @ctrl_data: Pointer to data structure for control function.
|
||||
*
|
||||
* Data needed or returned by the control function is stored in ctrl_data.
|
||||
*
|
||||
* This function returns:
|
||||
* 0: Control function completed successfully.
|
||||
* -EIO: Driver not initialized or error during control demod.
|
||||
* -EINVAL: Demod instance or ctrl_data has invalid content.
|
||||
* -ENOTSUPP: Specified control function is not available.
|
||||
*/
|
||||
|
||||
int drx_ctrl(struct drx_demod_instance *demod, u32 ctrl, void *ctrl_data)
|
||||
{
|
||||
int status = -EIO;
|
||||
|
||||
if ((demod == NULL) ||
|
||||
(demod->my_demod_funct == NULL) ||
|
||||
(demod->my_common_attr == NULL) ||
|
||||
(demod->my_ext_attr == NULL) || (demod->my_i2c_dev_addr == NULL)
|
||||
) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (((!demod->my_common_attr->is_opened) &&
|
||||
(ctrl != DRX_CTRL_PROBE_DEVICE) && (ctrl != DRX_CTRL_VERSION))
|
||||
) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((DRX_ISPOWERDOWNMODE(demod->my_common_attr->current_power_mode) &&
|
||||
(ctrl != DRX_CTRL_POWER_MODE) &&
|
||||
(ctrl != DRX_CTRL_PROBE_DEVICE) &&
|
||||
(ctrl != DRX_CTRL_NOP) && (ctrl != DRX_CTRL_VERSION)
|
||||
)
|
||||
) {
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
/* Fixed control functions */
|
||||
switch (ctrl) {
|
||||
/*======================================================================*/
|
||||
case DRX_CTRL_NOP:
|
||||
/* No operation */
|
||||
return 0;
|
||||
break;
|
||||
|
||||
/*======================================================================*/
|
||||
case DRX_CTRL_VERSION:
|
||||
return drx_ctrl_version(demod, (struct drx_version_list **)ctrl_data);
|
||||
break;
|
||||
|
||||
/*======================================================================*/
|
||||
default:
|
||||
/* Do nothing */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Virtual functions */
|
||||
/* First try calling function from derived class */
|
||||
status = (*(demod->my_demod_funct->ctrl_func)) (demod, ctrl, ctrl_data);
|
||||
if (status == -ENOTSUPP) {
|
||||
/* Now try calling a the base class function */
|
||||
switch (ctrl) {
|
||||
/*===================================================================*/
|
||||
case DRX_CTRL_LOAD_UCODE:
|
||||
return drx_ctrl_u_code(demod,
|
||||
(struct drxu_code_info *)ctrl_data,
|
||||
UCODE_UPLOAD);
|
||||
break;
|
||||
|
||||
/*===================================================================*/
|
||||
case DRX_CTRL_VERIFY_UCODE:
|
||||
{
|
||||
return drx_ctrl_u_code(demod,
|
||||
(struct drxu_code_info *)ctrl_data,
|
||||
UCODE_VERIFY);
|
||||
}
|
||||
break;
|
||||
|
||||
/*===================================================================*/
|
||||
default:
|
||||
pr_err("control %d not supported\n", ctrl);
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
} else {
|
||||
return status;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue