From patchwork Mon Mar 3 10:06:43 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mauro Carvalho Chehab X-Patchwork-Id: 3753181 Return-Path: X-Original-To: patchwork-linux-media@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id D1F68BF13A for ; Mon, 3 Mar 2014 10:15:03 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 61E262013D for ; Mon, 3 Mar 2014 10:15:01 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id F2FB22009C for ; Mon, 3 Mar 2014 10:14:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754441AbaCCKOw (ORCPT ); Mon, 3 Mar 2014 05:14:52 -0500 Received: from bombadil.infradead.org ([198.137.202.9]:49409 "EHLO bombadil.infradead.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754099AbaCCKIA (ORCPT ); Mon, 3 Mar 2014 05:08:00 -0500 Received: from [201.74.152.26] (helo=smtp.w2.samsung.com) by bombadil.infradead.org with esmtpsa (Exim 4.80.1 #2 (Red Hat Linux)) id 1WKPms-00078C-Cg; Mon, 03 Mar 2014 10:07:57 +0000 Received: from mchehab by smtp.w2.samsung.com with local (Exim 4.80.1) (envelope-from ) id 1WKPmF-0006Xc-F9; Mon, 03 Mar 2014 07:07:15 -0300 From: Mauro Carvalho Chehab Cc: Mauro Carvalho Chehab , Linux Media Mailing List , Mauro Carvalho Chehab Subject: [PATCH 49/79] [media] drx-j: get rid of drx_driver.c Date: Mon, 3 Mar 2014 07:06:43 -0300 Message-Id: <1393841233-24840-50-git-send-email-m.chehab@samsung.com> X-Mailer: git-send-email 1.8.5.3 In-Reply-To: <1393841233-24840-1-git-send-email-m.chehab@samsung.com> References: <1393841233-24840-1-git-send-email-m.chehab@samsung.com> To: unlisted-recipients:; (no To-header on input) Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drx39xyj/Makefile | 2 +- drivers/media/dvb-frontends/drx39xyj/drx_driver.c | 651 ---------------------- drivers/media/dvb-frontends/drx39xyj/drxj.c | 597 +++++++++++++++++++- 3 files changed, 593 insertions(+), 657 deletions(-) delete mode 100644 drivers/media/dvb-frontends/drx39xyj/drx_driver.c \ No newline at end of file diff --git a/drivers/media/dvb-frontends/drx39xyj/Makefile b/drivers/media/dvb-frontends/drx39xyj/Makefile index f84c5d87d771..d9ed094e0d18 100644 --- a/drivers/media/dvb-frontends/drx39xyj/Makefile +++ b/drivers/media/dvb-frontends/drx39xyj/Makefile @@ -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 diff --git a/drivers/media/dvb-frontends/drx39xyj/drx_driver.c b/drivers/media/dvb-frontends/drx39xyj/drx_driver.c deleted file mode 100644 index 0ebc0d285296..000000000000 --- a/drivers/media/dvb-frontends/drx39xyj/drx_driver.c +++ /dev/null @@ -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; -} diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index b1ad26b9778a..a06c45d92955 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -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; +}