[media] drx-j: dynamically load the firmware
Instead of hardcoding the firmware files together with the driver, use request_firmware() way, loading it from userspace. The firmware files are placed at: http://linuxtv.org/downloads/firmware/#8 And they'll be latter submitted to linux-firmware git tree. Acked-by: Devin Heitmueller <dheitmueller@kernellabs.com> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
This commit is contained in:
parent
782ae20df2
commit
b48293db4a
|
@ -29,9 +29,10 @@
|
|||
#include "dvb_frontend.h"
|
||||
#include "drx39xxj.h"
|
||||
#include "drx_driver.h"
|
||||
#include "drxj_mc.h"
|
||||
#include "drxj.h"
|
||||
|
||||
#define DRX39XX_MAIN_FIRMWARE "dvb-fe-drxj-mc-1.0.8.fw"
|
||||
|
||||
static int drx39xxj_set_powerstate(struct dvb_frontend *fe, int enable)
|
||||
{
|
||||
struct drx39xxj_state *state = fe->demodulator_priv;
|
||||
|
@ -323,6 +324,8 @@ static void drx39xxj_release(struct dvb_frontend *fe)
|
|||
kfree(demod->my_ext_attr);
|
||||
kfree(demod->my_common_attr);
|
||||
kfree(demod->my_i2c_dev_addr);
|
||||
if (demod->firmware)
|
||||
release_firmware(demod->firmware);
|
||||
kfree(demod);
|
||||
kfree(state);
|
||||
}
|
||||
|
@ -377,15 +380,13 @@ struct dvb_frontend *drx39xxj_attach(struct i2c_adapter *i2c)
|
|||
demod->my_i2c_dev_addr = demod_addr;
|
||||
demod->my_common_attr = demod_comm_attr;
|
||||
demod->my_i2c_dev_addr->user_data = state;
|
||||
demod->my_common_attr->microcode = DRXJ_MC_MAIN;
|
||||
#if 0
|
||||
demod->my_common_attr->verify_microcode = false;
|
||||
#endif
|
||||
demod->my_common_attr->microcode_file = DRX39XX_MAIN_FIRMWARE;
|
||||
demod->my_common_attr->verify_microcode = true;
|
||||
demod->my_common_attr->intermediate_freq = 5000;
|
||||
demod->my_ext_attr = demod_ext_attr;
|
||||
((struct drxj_data *)demod_ext_attr)->uio_sma_tx_mode = DRX_UIO_MODE_READWRITE;
|
||||
demod->my_tuner = NULL;
|
||||
demod->i2c = i2c;
|
||||
|
||||
result = drx_open(demod);
|
||||
if (result != 0) {
|
||||
|
@ -455,3 +456,4 @@ static struct dvb_frontend_ops drx39xxj_ops = {
|
|||
MODULE_DESCRIPTION("Micronas DRX39xxj Frontend");
|
||||
MODULE_AUTHOR("Devin Heitmueller");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_FIRMWARE(DRX39XX_MAIN_FIRMWARE);
|
||||
|
|
|
@ -33,6 +33,7 @@ struct drx39xxj_state {
|
|||
struct dvb_frontend frontend;
|
||||
int powered_up:1;
|
||||
unsigned int i2c_gate_open:1;
|
||||
const struct firmware *fw;
|
||||
};
|
||||
|
||||
struct dvb_frontend *drx39xxj_attach(struct i2c_adapter *i2c);
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
/*
|
||||
Generic DRX functionality, DRX driver core.
|
||||
|
||||
Copyright (c), 2004-2005,2007-2010 Trident Microsystems, Inc.
|
||||
All rights reserved.
|
||||
|
||||
|
@ -28,12 +30,8 @@
|
|||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file $Id: drx_driver.c,v 1.40 2010/01/12 01:24:56 lfeng Exp $
|
||||
*
|
||||
* \brief Generic DRX functionality, DRX driver core.
|
||||
*
|
||||
*/
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
INCLUDE FILES
|
||||
|
@ -957,32 +955,64 @@ static int
|
|||
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;
|
||||
u8 *mc_data = (u8 *)(NULL);
|
||||
struct i2c_device_addr *dev_addr = (struct i2c_device_addr *)(NULL);
|
||||
|
||||
dev_addr = demod->my_i2c_dev_addr;
|
||||
const u8 *mc_data_init = NULL;
|
||||
u8 *mc_data = NULL;
|
||||
char *mc_file = mc_info->mc_file;
|
||||
|
||||
/* Check arguments */
|
||||
if ((mc_info == NULL) || (mc_info->mc_data == NULL))
|
||||
if (!mc_info || !mc_file)
|
||||
return -EINVAL;
|
||||
|
||||
mc_data = mc_info->mc_data;
|
||||
if (demod->firmware) {
|
||||
mc_data_init = demod->firmware->data;
|
||||
mc_data = (void *)mc_data_init;
|
||||
|
||||
/* Check data */
|
||||
mc_magic_word = u_code_read16(mc_data);
|
||||
mc_data += sizeof(u16);
|
||||
mc_nr_of_blks = u_code_read16(mc_data);
|
||||
mc_data += sizeof(u16);
|
||||
/* Check data */
|
||||
mc_magic_word = u_code_read16(mc_data);
|
||||
mc_data += sizeof(u16);
|
||||
mc_nr_of_blks = u_code_read16(mc_data);
|
||||
mc_data += sizeof(u16);
|
||||
} else {
|
||||
const struct firmware *fw = NULL;
|
||||
unsigned size = 0;
|
||||
|
||||
if ((mc_magic_word != DRX_UCODE_MAGIC_WORD) || (mc_nr_of_blks == 0))
|
||||
return -EINVAL; /* wrong endianess or wrong data ? */
|
||||
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;
|
||||
mc_data_init = demod->firmware->data;
|
||||
size = demod->firmware->size;
|
||||
|
||||
pr_info("Firmware %s, size %u\n", mc_file, size);
|
||||
|
||||
mc_data = (void *)mc_data_init;
|
||||
/* Check data */
|
||||
if (mc_data - mc_data_init + 2 * sizeof(u16) > size)
|
||||
goto eof;
|
||||
mc_magic_word = u_code_read16(mc_data);
|
||||
mc_data += sizeof(u16);
|
||||
mc_nr_of_blks = u_code_read16(mc_data);
|
||||
mc_data += sizeof(u16);
|
||||
|
||||
|
||||
if ((mc_magic_word != DRX_UCODE_MAGIC_WORD) || (mc_nr_of_blks == 0)) {
|
||||
rc = -EINVAL; /* wrong endianess or wrong data ? */
|
||||
pr_err("Firmware magic word doesn't match\n");
|
||||
goto release;
|
||||
}
|
||||
|
||||
/*
|
||||
* Scan microcode blocks first for version info
|
||||
* and firmware check
|
||||
*/
|
||||
|
||||
/* Scan microcode blocks first for version info if uploading */
|
||||
if (action == UCODE_UPLOAD) {
|
||||
/* Clear version block */
|
||||
DRX_ATTR_MCRECORD(demod).aux_type = 0;
|
||||
DRX_ATTR_MCRECORD(demod).mc_dev_type = 0;
|
||||
|
@ -991,6 +1021,9 @@ ctrl_u_code(struct drx_demod_instance *demod,
|
|||
for (i = 0; i < mc_nr_of_blks; i++) {
|
||||
struct drxu_code_block_hdr block_hdr;
|
||||
|
||||
if (mc_data - mc_data_init +
|
||||
3 * sizeof(u16) + sizeof(u32) > size)
|
||||
goto eof;
|
||||
/* Process block header */
|
||||
block_hdr.addr = u_code_read32(mc_data);
|
||||
mc_data += sizeof(u32);
|
||||
|
@ -1002,9 +1035,15 @@ ctrl_u_code(struct drx_demod_instance *demod,
|
|||
mc_data += sizeof(u16);
|
||||
|
||||
if (block_hdr.flags & 0x8) {
|
||||
u8 *auxblk = ((void *)mc_data_init) + block_hdr.addr;
|
||||
u16 auxtype;
|
||||
|
||||
if (mc_data - mc_data_init + sizeof(u16) +
|
||||
2 * sizeof(u32) > size)
|
||||
goto eof;
|
||||
|
||||
/* Aux block. Check type */
|
||||
u8 *auxblk = mc_info->mc_data + block_hdr.addr;
|
||||
u16 auxtype = u_code_read16(auxblk);
|
||||
auxtype = u_code_read16(auxblk);
|
||||
if (DRX_ISMCVERTYPE(auxtype)) {
|
||||
DRX_ATTR_MCRECORD(demod).aux_type = u_code_read16(auxblk);
|
||||
auxblk += sizeof(u16);
|
||||
|
@ -1015,20 +1054,28 @@ ctrl_u_code(struct drx_demod_instance *demod,
|
|||
DRX_ATTR_MCRECORD(demod).mc_base_version = u_code_read32(auxblk);
|
||||
}
|
||||
}
|
||||
if (mc_data - mc_data_init +
|
||||
block_hdr.size * sizeof(u16) > size)
|
||||
goto eof;
|
||||
|
||||
/* Next block */
|
||||
mc_data += block_hdr.size * sizeof(u16);
|
||||
}
|
||||
|
||||
/* Restore data pointer */
|
||||
mc_data = ((void *)mc_data_init) + 2 * sizeof(u16);
|
||||
}
|
||||
|
||||
if (action == UCODE_UPLOAD) {
|
||||
/* 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)
|
||||
return rc;
|
||||
|
||||
/* Restore data pointer */
|
||||
mc_data = mc_info->mc_data + 2 * sizeof(u16);
|
||||
if (rc != 0 && rc != -ENOTSUPP) {
|
||||
pr_err("Validate ucode not supported\n");
|
||||
goto release;
|
||||
}
|
||||
pr_info("Uploading firmware %s\n", mc_file);
|
||||
}
|
||||
|
||||
/* Process microcode blocks */
|
||||
|
@ -1055,103 +1102,85 @@ ctrl_u_code(struct drx_demod_instance *demod,
|
|||
(block_hdr.CRC != u_code_compute_crc(mc_data, block_hdr.size)))
|
||||
) {
|
||||
/* Wrong data ! */
|
||||
return -EINVAL;
|
||||
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));
|
||||
|
||||
if (block_hdr.size != 0) {
|
||||
/* Perform the desired action */
|
||||
switch (action) {
|
||||
/*================================================================*/
|
||||
case UCODE_UPLOAD:
|
||||
{
|
||||
/* Upload microcode */
|
||||
if (demod->my_access_funct->
|
||||
write_block_func(dev_addr,
|
||||
(dr_xaddr_t) block_hdr.
|
||||
addr, mc_block_nr_bytes,
|
||||
mc_data,
|
||||
0x0000) !=
|
||||
0) {
|
||||
return -EIO;
|
||||
} /* if */
|
||||
/* 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)) {
|
||||
pr_err("error writing firmware\n");
|
||||
goto release;
|
||||
}
|
||||
break;
|
||||
case UCODE_VERIFY: {
|
||||
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\n");
|
||||
goto release;
|
||||
}
|
||||
break;
|
||||
|
||||
/*================================================================*/
|
||||
case UCODE_VERIFY:
|
||||
{
|
||||
int result = 0;
|
||||
u8 mc_data_buffer
|
||||
[DRX_UCODE_MAX_BUF_SIZE];
|
||||
u32 bytes_to_compare = 0;
|
||||
u32 bytes_left_to_compare = 0;
|
||||
u32 curr_addr = (dr_xaddr_t) 0;
|
||||
u8 *curr_ptr = NULL;
|
||||
result =drxbsp_hst_memcmp(curr_ptr,
|
||||
mc_data_buffer,
|
||||
bytes_to_comp);
|
||||
|
||||
bytes_left_to_compare = mc_block_nr_bytes;
|
||||
curr_addr = block_hdr.addr;
|
||||
curr_ptr = mc_data;
|
||||
|
||||
while (bytes_left_to_compare != 0) {
|
||||
if (bytes_left_to_compare >
|
||||
((u32)
|
||||
DRX_UCODE_MAX_BUF_SIZE)) {
|
||||
bytes_to_compare =
|
||||
((u32)
|
||||
DRX_UCODE_MAX_BUF_SIZE);
|
||||
} else {
|
||||
bytes_to_compare =
|
||||
bytes_left_to_compare;
|
||||
}
|
||||
|
||||
if (demod->my_access_funct->
|
||||
read_block_func(dev_addr,
|
||||
curr_addr,
|
||||
(u16)
|
||||
bytes_to_compare,
|
||||
(u8 *)
|
||||
mc_data_buffer,
|
||||
0x0000) !=
|
||||
0) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
result =
|
||||
drxbsp_hst_memcmp(curr_ptr,
|
||||
mc_data_buffer,
|
||||
bytes_to_compare);
|
||||
|
||||
if (result != 0)
|
||||
return -EIO;
|
||||
|
||||
curr_addr +=
|
||||
((dr_xaddr_t)
|
||||
(bytes_to_compare / 2));
|
||||
curr_ptr =
|
||||
&(curr_ptr[bytes_to_compare]);
|
||||
bytes_left_to_compare -=
|
||||
((u32) bytes_to_compare);
|
||||
} /* while( bytes_to_compare > DRX_UCODE_MAX_BUF_SIZE ) */
|
||||
if (result) {
|
||||
pr_err("error verifying firmware\n");
|
||||
return -EIO;
|
||||
}
|
||||
break;
|
||||
|
||||
/*================================================================*/
|
||||
default:
|
||||
return -EINVAL;
|
||||
break;
|
||||
|
||||
} /* switch ( action ) */
|
||||
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;
|
||||
|
||||
/* if (block_hdr.size != 0 ) */
|
||||
/* Next block */
|
||||
}
|
||||
mc_data += mc_block_nr_bytes;
|
||||
|
||||
} /* for( i = 0 ; i<mc_nr_of_blks ; i++ ) */
|
||||
}
|
||||
|
||||
return 0;
|
||||
eof:
|
||||
rc = -ENOENT;
|
||||
pr_err("Firmware file %s is truncated at pos %lu\n",
|
||||
mc_file, (unsigned long)(mc_data - mc_data_init));
|
||||
release:
|
||||
release_firmware(demod->firmware);
|
||||
demod->firmware = NULL;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*============================================================================*/
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/i2c.h>
|
||||
|
||||
/*
|
||||
* This structure contains the I2C address, the device ID and a user_data pointer.
|
||||
|
@ -1014,13 +1016,14 @@ STRUCTS
|
|||
/*============================================================================*/
|
||||
|
||||
/**
|
||||
* \struct struct drxu_code_info * \brief Parameters for microcode upload and verfiy.
|
||||
*
|
||||
* Used by DRX_CTRL_LOAD_UCODE and DRX_CTRL_VERIFY_UCODE
|
||||
*/
|
||||
* struct drxu_code_info Parameters for microcode upload and verfiy.
|
||||
*
|
||||
* @mc_file: microcode file name
|
||||
*
|
||||
* Used by DRX_CTRL_LOAD_UCODE and DRX_CTRL_VERIFY_UCODE
|
||||
*/
|
||||
struct drxu_code_info {
|
||||
u8 *mc_data;
|
||||
/**< Pointer to microcode image. */
|
||||
char *mc_file;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1929,8 +1932,7 @@ struct drx_reg_dump {
|
|||
*/
|
||||
struct drx_common_attr {
|
||||
/* Microcode (firmware) attributes */
|
||||
u8 *microcode; /**< Pointer to microcode image. */
|
||||
/**< Size of microcode image in bytes. */
|
||||
char *microcode_file; /**< microcode filename */
|
||||
bool verify_microcode;
|
||||
/**< Use microcode verify or not. */
|
||||
struct drx_mc_version_rec mcversion;
|
||||
|
@ -2029,21 +2031,24 @@ struct drx_demod_instance;
|
|||
/**
|
||||
* \struct struct drx_demod_instance * \brief Top structure of demodulator instance.
|
||||
*/
|
||||
struct drx_demod_instance {
|
||||
/* type specific demodulator data */
|
||||
struct drx_demod_func *my_demod_funct;
|
||||
/**< demodulator functions */
|
||||
struct drx_access_func *my_access_funct;
|
||||
/**< data access protocol functions */
|
||||
struct tuner_instance *my_tuner;
|
||||
/**< tuner instance,if NULL then baseband */
|
||||
struct i2c_device_addr *my_i2c_dev_addr;
|
||||
/**< i2c address and device identifier */
|
||||
struct drx_common_attr *my_common_attr;
|
||||
/**< common DRX attributes */
|
||||
void *my_ext_attr; /**< device specific attributes */
|
||||
/* generic demodulator data */
|
||||
};
|
||||
struct drx_demod_instance {
|
||||
/* type specific demodulator data */
|
||||
struct drx_demod_func *my_demod_funct;
|
||||
/**< demodulator functions */
|
||||
struct drx_access_func *my_access_funct;
|
||||
/**< data access protocol functions */
|
||||
struct tuner_instance *my_tuner;
|
||||
/**< tuner instance,if NULL then baseband */
|
||||
struct i2c_device_addr *my_i2c_dev_addr;
|
||||
/**< i2c address and device identifier */
|
||||
struct drx_common_attr *my_common_attr;
|
||||
/**< common DRX attributes */
|
||||
void *my_ext_attr; /**< device specific attributes */
|
||||
/* generic demodulator data */
|
||||
|
||||
struct i2c_adapter *i2c;
|
||||
const struct firmware *firmware;
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
MACROS
|
||||
|
|
|
@ -875,7 +875,7 @@ struct i2c_device_addr drxj_default_addr_g = {
|
|||
* \brief Default common attributes of a drxj demodulator instance.
|
||||
*/
|
||||
struct drx_common_attr drxj_default_comm_attr_g = {
|
||||
(u8 *)NULL, /* ucode ptr */
|
||||
NULL, /* ucode file */
|
||||
true, /* ucode verify switch */
|
||||
{0}, /* version record */
|
||||
|
||||
|
@ -20139,11 +20139,11 @@ int drxj_open(struct drx_demod_instance *demod)
|
|||
}
|
||||
|
||||
/* Upload microcode */
|
||||
if (common_attr->microcode != NULL) {
|
||||
if (common_attr->microcode_file != NULL) {
|
||||
/* Dirty trick to use common ucode upload & verify,
|
||||
pretend device is already open */
|
||||
common_attr->is_opened = true;
|
||||
ucode_info.mc_data = common_attr->microcode;
|
||||
ucode_info.mc_file = common_attr->microcode_file;
|
||||
|
||||
#ifdef DRXJ_SPLIT_UCODE_UPLOAD
|
||||
/* Upload microcode without audio part */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue