* [PATCH 12/17]DVB:Siano drivers - Improve firmware load and reload mechanism.
@ 2011-09-20 10:31 Doron Cohen
2011-09-23 22:44 ` Mauro Carvalho Chehab
0 siblings, 1 reply; 2+ messages in thread
From: Doron Cohen @ 2011-09-20 10:31 UTC (permalink / raw)
To: linux-media
Hi,
This patch step Improve firmware load and reload mechanism in order to
support new siano devices and match all existing devices.
Thanks,
Doron Cohen
-----------------------
>From 59062b9fbc2f3c28cbb1ec014c6ed5a3e065a7de Mon Sep 17 00:00:00 2001
From: Doron Cohen <doronc@siano-ms.com>
Date: Tue, 20 Sep 2011 08:22:29 +0300
Subject: [PATCH 16/21] Improve firmware load and reload mechanism in
order to support new siano devices and match all existing devices.
---
drivers/media/dvb/siano/smscoreapi.c | 530
+++++++++++++++++++++++++++-------
1 files changed, 423 insertions(+), 107 deletions(-)
diff --git a/drivers/media/dvb/siano/smscoreapi.c
b/drivers/media/dvb/siano/smscoreapi.c
index db24391..e50e356 100644
--- a/drivers/media/dvb/siano/smscoreapi.c
+++ b/drivers/media/dvb/siano/smscoreapi.c
@@ -312,6 +312,7 @@ smscore_buffer_t *smscore_createbuffer(u8 *buffer,
void *common_buffer,
cb->p = buffer;
cb->offset_in_common = buffer - (u8 *) common_buffer;
cb->phys = common_buffer_phys + cb->offset_in_common;
+ cb->offset=0;
return cb;
}
@@ -352,6 +353,7 @@ int smscore_register_device(struct
smsdevice_params_t *params,
/* init completion events */
init_completion(&dev->version_ex_done);
init_completion(&dev->data_download_done);
+ init_completion(&dev->data_validity_done);
init_completion(&dev->trigger_done);
init_completion(&dev->init_device_done);
init_completion(&dev->reload_start_done);
@@ -360,6 +362,7 @@ int smscore_register_device(struct
smsdevice_params_t *params,
init_completion(&dev->gpio_set_level_done);
init_completion(&dev->gpio_get_level_done);
init_completion(&dev->ir_init_done);
+ init_completion(&dev->device_ready_done);
/* Buffer management */
init_waitqueue_head(&dev->buffer_mng_waitq);
@@ -426,7 +429,13 @@ EXPORT_SYMBOL_GPL(smscore_register_device);
static int smscore_sendrequest_and_wait(struct smscore_device_t
*coredev,
void *buffer, size_t size, struct completion *completion) {
- int rc = coredev->sendrequest_handler(coredev->context, buffer, size);
+ int rc;
+
+ if (completion == NULL)
+ return -EINVAL;
+ init_completion(completion);
+
+ rc = coredev->sendrequest_handler(coredev->context, buffer, size);
if (rc < 0) {
sms_info("sendrequest returned error %d", rc);
return rc;
@@ -535,7 +544,8 @@ static int smscore_load_firmware_family2(struct
smscore_device_t *coredev,
{
struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer;
struct SmsMsgHdr_S *msg;
- u32 mem_address;
+ u32 mem_address, calc_checksum = 0;
+ u32 i, *ptr;
u8 *payload = firmware->Payload;
int rc = 0;
firmware->StartAddress = le32_to_cpu(firmware->StartAddress);
@@ -563,9 +573,17 @@ static int smscore_load_firmware_family2(struct
smscore_device_t *coredev,
rc = smscore_sendrequest_and_wait(coredev, msg,
msg->msgLength,
&coredev->reload_start_done);
+
+ if (rc < 0) {
+ sms_err("device reload failed, rc %d", rc);
+ goto exit_fw_download;
+ }
+
mem_address = *(u32 *) &payload[20];
}
+ for (i = 0, ptr = (u32*)firmware->Payload; i < firmware->Length/4 ; i
++, ptr++)
+ calc_checksum += *ptr;
while (size && rc >= 0) {
struct SmsDataDownload_S *DataMsg =
(struct SmsDataDownload_S *) msg;
@@ -578,14 +596,9 @@ static int smscore_load_firmware_family2(struct
smscore_device_t *coredev,
DataMsg->MemAddr = mem_address;
memcpy(DataMsg->Payload, payload, payload_size);
- if ((coredev->device_flags & SMS_ROM_NO_RESPONSE) &&
- (coredev->mode == SMSHOSTLIB_DEVMD_NONE))
- rc = coredev->sendrequest_handler(
- coredev->context, DataMsg,
- DataMsg->xMsgHeader.msgLength);
- else
- rc = smscore_sendrequest_and_wait(
- coredev, DataMsg,
+
+
+ rc = smscore_sendrequest_and_wait(coredev, DataMsg,
DataMsg->xMsgHeader.msgLength,
&coredev->data_download_done);
@@ -594,44 +607,63 @@ static int smscore_load_firmware_family2(struct
smscore_device_t *coredev,
mem_address += payload_size;
}
- if (rc >= 0) {
+ if (rc < 0)
+ goto exit_fw_download;
+
+ sms_err("sending MSG_SMS_DATA_VALIDITY_REQ expecting 0x%x",
calc_checksum);
+ SMS_INIT_MSG(msg, MSG_SMS_DATA_VALIDITY_REQ,
+ sizeof(struct SmsMsgHdr_S) +
+ sizeof(u32) * 3);
+ ((struct SmsMsgData_S *)msg)->msgData[0] = firmware->StartAddress;
+ /* Entry point */
+ ((struct SmsMsgData_S *)msg)->msgData[1] = firmware->Length;
+ ((struct SmsMsgData_S *)msg)->msgData[2] = 0; /* Regular checksum*/
+ smsendian_handle_tx_message((struct SmsMsgHdr_S *)msg);
+ rc = smscore_sendrequest_and_wait(coredev, msg, ((struct SmsMsgData_S
*)msg)->xMsgHeader.msgLength, &coredev->data_validity_done);
+ if (rc < 0)
+ goto exit_fw_download;
+
+
if (coredev->mode == SMSHOSTLIB_DEVMD_NONE) {
struct SmsMsgData_S *TriggerMsg =
(struct SmsMsgData_S *) msg;
+ sms_debug("sending MSG_SMS_SWDOWNLOAD_TRIGGER_REQ");
SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ,
sizeof(struct SmsMsgHdr_S) +
sizeof(u32) * 5);
TriggerMsg->msgData[0] = firmware->StartAddress;
/* Entry point */
- TriggerMsg->msgData[1] = 5; /* Priority */
+ TriggerMsg->msgData[1] = 6; /* Priority */
TriggerMsg->msgData[2] = 0x200; /* Stack size */
TriggerMsg->msgData[3] = 0; /* Parameter */
TriggerMsg->msgData[4] = 4; /* Task ID */
- if (coredev->device_flags & SMS_ROM_NO_RESPONSE) {
- rc = coredev->sendrequest_handler(
- coredev->context, TriggerMsg,
- TriggerMsg->xMsgHeader.msgLength);
- msleep(100);
- } else
- rc = smscore_sendrequest_and_wait(
- coredev, TriggerMsg,
+ smsendian_handle_tx_message((struct SmsMsgHdr_S *)msg);
+ rc = smscore_sendrequest_and_wait(coredev,
+ TriggerMsg,
TriggerMsg->xMsgHeader.msgLength,
&coredev->trigger_done);
} else {
SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ,
sizeof(struct SmsMsgHdr_S));
-
- rc = coredev->sendrequest_handler(coredev->context,
- msg, msg->msgLength);
- }
- msleep(500);
+ smsendian_handle_tx_message((struct SmsMsgHdr_S *)msg);
+ rc = coredev->sendrequest_handler(coredev->context, msg,
+ msg->msgLength);
}
- sms_debug("rc=%d, postload=%p ", rc,
- coredev->postload_handler);
+ if (rc < 0)
+ goto exit_fw_download;
+
+ /*
+ * backward compatibility - wait to device_ready_done for
+ * not more than 400 ms
+ */
+ msleep(400);
+
+exit_fw_download:
+ sms_debug("rc=%d, postload=0x%p ", rc, coredev->postload_handler);
kfree(msg);
@@ -653,42 +685,211 @@ static int smscore_load_firmware_family2(struct
smscore_device_t *coredev,
* @return 0 on success, <0 on error.
*/
static int smscore_load_firmware_from_file(struct smscore_device_t
*coredev,
- char *filename,
- loadfirmware_t loadfirmware_handler)
-{
+ int mode, int lookup, loadfirmware_t loadfirmware_handler) {
int rc = -ENOENT;
+ u8 *fw_buf;
+ u32 fw_buf_size;
+
+#ifdef REQUEST_FIRMWARE_SUPPORTED
const struct firmware *fw;
- u8 *fw_buffer;
- if (loadfirmware_handler == NULL && !(coredev->device_flags &
- SMS_DEVICE_FAMILY2))
+ char* fw_filename = smscore_get_fw_filename(coredev, mode, lookup);
+ if (!strcmp(fw_filename,"none"))
+ return -ENOENT;
+
+ if (loadfirmware_handler == NULL && !(coredev->device_flags
+ & SMS_DEVICE_FAMILY2))
return -EINVAL;
- rc = request_firmware(&fw, filename, coredev->device);
+ rc = request_firmware(&fw, fw_filename, coredev->device);
if (rc < 0) {
- sms_info("failed to open \"%s\"", filename);
+ sms_info("failed to open \"%s\"", fw_filename);
return rc;
}
- sms_info("read FW %s, size=%zd", filename, fw->size);
- fw_buffer = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT),
+ sms_info("read fw %s, buffer size=0x%x", fw_filename, fw->size);
+ fw_buf = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT),
GFP_KERNEL | GFP_DMA);
- if (fw_buffer) {
- memcpy(fw_buffer, fw->data, fw->size);
+ if (!fw_buf) {
+ sms_info("failed to allocate firmware buffer");
+ return -ENOMEM;
+ }
+ memcpy(fw_buf, fw->data, fw->size);
+ fw_buf_size = fw->size;
+#else
+ if (!coredev->fw_buf) {
+ sms_info("missing fw file buffer");
+ return -EINVAL;
+ }
+ fw_buf = coredev->fw_buf;
+ fw_buf_size = coredev->fw_buf_size;
+#endif
rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ?
- smscore_load_firmware_family2(coredev,
- fw_buffer,
- fw->size) :
- loadfirmware_handler(coredev->context,
- fw_buffer, fw->size);
+ smscore_load_firmware_family2(coredev, fw_buf, fw_buf_size)
+ : loadfirmware_handler(coredev->context, fw_buf,
+ fw_buf_size);
+
+ kfree(fw_buf);
+
+#ifdef REQUEST_FIRMWARE_SUPPORTED
+ release_firmware(fw);
+#else
+ coredev->fw_buf = NULL;
+ coredev->fw_buf_size = 0;
+#endif
+ return rc;
+}
+
+/**
+ * Send chunk of firmware data using SMS MSGs
+ * The motivation is to eliminate the need of big memory allocation in
kernel for firmware
+ * download.
+ *
+ * @param coredev pointer to a coredev object returned by
+ * smscore_register_device
+ * @param buffer pointer to a buffer
+ * @param size size of buffer
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_send_fw_chunk(struct smscore_device_t *coredev,
+ void *buffer, size_t size)
+{
+
+ struct SmsMsgHdr_S *msg;
+ int rc = 0;
+ int offset = 0;
+
+ if (buffer == NULL)
+ {
+ sms_debug("Error: NULL buffer");
+ return -1;
+ }
+
+ /* First chunk */
+ if (coredev->start_address == 0)
+ {
+ struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer;
+ coredev->start_address = le32_to_cpu(firmware->StartAddress);
+ coredev->current_address = coredev->start_address;
+ offset = 12;
+ size -= 12;
+
+ if (coredev->preload_handler)
+ {
+ rc = coredev->preload_handler(coredev->context);
+ if (rc < 0)
+ return rc;
+ }
+ }
+
+ /* PAGE_SIZE buffer shall be enough and dma aligned */
+ msg = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
+ if (!msg)
+ return -ENOMEM;
+
+ while (size && rc >= 0) {
+ int payload_size;
+ struct SmsDataDownload_S *DataMsg;
+ sms_debug("sending MSG_SMS_DATA_DOWNLOAD_REQ");
+ DataMsg = (struct SmsDataDownload_S *) msg;
+ payload_size = min((int)size, SMS_MAX_PAYLOAD_SIZE);
- kfree(fw_buffer);
+ SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ,
+ (u16) (sizeof(struct SmsMsgHdr_S) +
+ sizeof(u32) + payload_size));
+
+ DataMsg->MemAddr = coredev->current_address;
+ copy_from_user(DataMsg->Payload, (u8*)(buffer + offset),
payload_size);
+
+ smsendian_handle_tx_message((struct SmsMsgHdr_S *)msg);
+ rc = smscore_sendrequest_and_wait(coredev, DataMsg,
+ DataMsg->xMsgHeader.msgLength,
+ &coredev->data_download_done);
+
+ size -= payload_size;
+ offset += payload_size;
+ coredev->current_address += payload_size;
+ }
+
+ kfree(msg);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(smscore_send_fw_chunk);
+
+
+/**
+ * Send last chunk of firmware data using SMS MSGs
+ *
+ * @param coredev pointer to a coredev object returned by
+ * smscore_register_device
+ * @param buffer pointer to a buffer
+ * @param size size of buffer
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_send_last_fw_chunk(struct smscore_device_t *coredev,
+ void *buffer, size_t size)
+{
+ int rc = 0;
+ struct SmsMsgHdr_S *msg;
+
+ rc = smscore_send_fw_chunk(coredev, buffer, size);
+ if (rc < 0)
+ return rc;
+
+ /* PAGE_SIZE buffer shall be enough and dma aligned */
+ msg = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
+ if (!msg)
+ return -ENOMEM;
+
+ if (coredev->mode == SMSHOSTLIB_DEVMD_NONE) {
+ struct SmsMsgData_S *TriggerMsg =
+ (struct SmsMsgData_S *) msg;
+
+ sms_debug("sending MSG_SMS_SWDOWNLOAD_TRIGGER_REQ");
+ SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ,
+ sizeof(struct SmsMsgHdr_S) +
+ sizeof(u32) * 5);
+
+ TriggerMsg->msgData[0] = coredev->start_address;
+ /* Entry point */
+ TriggerMsg->msgData[1] = 6; /* Priority */
+ TriggerMsg->msgData[2] = 0x200; /* Stack size */
+ TriggerMsg->msgData[3] = 0; /* Parameter */
+ TriggerMsg->msgData[4] = 4; /* Task ID */
+
+ smsendian_handle_tx_message((struct SmsMsgHdr_S *)msg);
+ rc = smscore_sendrequest_and_wait(coredev,
+ TriggerMsg,
+ TriggerMsg->xMsgHeader.msgLength,
+ &coredev->trigger_done);
} else {
- sms_info("failed to allocate firmware buffer");
- rc = -ENOMEM;
+ SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ,
+ sizeof(struct SmsMsgHdr_S));
+ smsendian_handle_tx_message((struct SmsMsgHdr_S *)msg);
+ rc = coredev->sendrequest_handler(coredev->context, msg,
+ msg->msgLength);
}
- release_firmware(fw);
+ /* clear start_address */
+ coredev->start_address = 0;
+
+ if (rc < 0)
+ goto exit_fw_download;
+
+ /*
+ * backward compatibility - wait to device_ready_done for
+ * not more than 400 ms
+ */
+ wait_for_completion_timeout(&coredev->device_ready_done,
+ msecs_to_jiffies(400));
+
+exit_fw_download:
+ sms_debug("rc=%d, postload=0x%p ", rc, coredev->postload_handler);
+
+ kfree(msg);
return rc;
}
@@ -712,6 +913,7 @@ void smscore_unregister_device(struct
smscore_device_t *coredev)
/* Release input device (IR) resources */
#ifdef SMS_RC_SUPPORT_SUBSYS
+ /* Release input device (IR) resources */
sms_ir_exit(coredev);
#endif /*SMS_RC_SUPPORT_SUBSYS*/
smscore_notify_clients(coredev);
@@ -737,7 +939,9 @@ void smscore_unregister_device(struct
smscore_device_t *coredev)
sms_info("waiting for %d buffer(s)",
coredev->num_buffers - num_buffers);
+ kmutex_unlock(&g_smscore_deviceslock);
msleep(100);
+ kmutex_lock(&g_smscore_deviceslock);
}
sms_info("freed %d buffers", num_buffers);
@@ -800,30 +1004,106 @@ static int smscore_detect_mode(struct
smscore_device_t *coredev)
}
static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = {
- /*Stellar NOVA A0 Nova B0 VEGA*/
+/*Stellar, NOVA A0, Nova B0, VEGA, VENICE, MING, PELE, RIO,
DENVER_1530, DENVER_2160*/
/*DVBT*/
- {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
+{ "none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none",
"none", "none", "none", "dvb_rio.inp", "none", "none" },
/*DVBH*/
- {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
+{ "none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none",
"none", "none", "none", "dvbh_rio.inp", "none", "none" },
/*TDMB*/
- {"none", "tdmb_nova_12mhz.inp", "tdmb_nova_12mhz_b0.inp", "none"},
+{ "none", "tdmb_nova_12mhz.inp", "tdmb_nova_12mhz_b0.inp", "none",
"none", "none", "none", "none", "none", "tdmb_denver.inp" },
/*DABIP*/
- {"none", "none", "none", "none"},
- /*BDA*/
- {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
+{ "none", "none", "none", "none", "none", "none", "none", "none",
"none", "none" },
+/*DVBT_BDA*/
+{ "none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none",
"none", "none", "none", "dvb_rio.inp", "none", "none" },
/*ISDBT*/
- {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
- /*ISDBTBDA*/
- {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
+{ "none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none",
"none", "none", "isdbt_pele.inp", "isdbt_rio.inp", "none", "none" },
+/*ISDBT_BDA*/
+{ "none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none",
"none", "none", "isdbt_pele.inp", "isdbt_rio.inp", "none", "none" },
/*CMMB*/
- {"none", "none", "none", "cmmb_vega_12mhz.inp"}
+{ "none", "none", "none", "cmmb_vega_12mhz.inp",
"cmmb_venice_12mhz.inp", "cmmb_ming_app.inp", "none", "none", "none",
"none" },
+/*RAW - not supported*/
+{ "none", "none", "none", "none", "none", "none", "none", "none",
"none", "none" },
+/*FM*/
+{ "none", "none", "fm_radio.inp", "none", "none", "none", "none",
"fm_radio_rio.inp", "none", "none" },
+/*FM_BDA*/
+{ "none", "none", "fm_radio.inp", "none", "none", "none", "none",
"fm_radio_rio.inp", "none", "none" },
+/*ATSC*/
+{ "none", "none", "none", "none", "none", "none", "none", "none",
"atsc_denver.inp", "none" }
};
-static inline char *sms_get_fw_name(struct smscore_device_t *coredev,
- int mode, enum sms_device_type_st type)
+/**
+ * get firmware file name from one of the two mechanisms : sms_boards
or
+ * smscore_fw_lkup.
+
+ * @param coredev pointer to a coredev object returned by
+ * smscore_register_device
+ * @param mode requested mode of operation
+ * @param lookup if 1, always get the fw filename from smscore_fw_lkup
+ * table. if 0, try first to get from sms_boards
+ *
+ * @return 0 on success, <0 on error.
+ */
+char *smscore_get_fw_filename(struct smscore_device_t *coredev, int
mode, int lookup) {
+ char **fw;
+ int board_id = smscore_get_board_id(coredev);
+ enum sms_device_type_st type =
smscore_registry_gettype(coredev->devpath);
+
+ if ( (board_id == SMS_BOARD_UNKNOWN) ||
+ (lookup == 1) ) {
+ sms_debug("trying to get fw name from lookup table mode %d type %d",
mode, type);
+ return smscore_fw_lkup[mode][type];
+ }
+
+ sms_debug("trying to get fw name from sms_boards board_id %d mode %d",
board_id, mode);
+ fw = sms_get_board(board_id)->fw;
+ if (fw == NULL) {
+ sms_debug("cannot find fw name in sms_boards, getting from lookup
table mode %d type %d", mode, type);
+ return smscore_fw_lkup[mode][type];
+ }
+
+ if (fw[mode] == NULL) {
+ sms_debug("cannot find fw name in sms_boards, getting from lookup
table mode %d type %d", mode, type);
+ return smscore_fw_lkup[mode][type];
+ }
+
+ return fw[mode];
+}
+
+/**
+ * send init device request and wait for response
+ *
+ * @param coredev pointer to a coredev object returned by
+ * smscore_register_device
+ * @param mode requested mode of operation
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_init_device(struct smscore_device_t *coredev, int mode)
{
- char **fw = sms_get_board(smscore_get_board_id(coredev))->fw;
- return (fw && fw[mode]) ? fw[mode] : smscore_fw_lkup[mode][type];
+ void* buffer;
+ struct SmsMsgData_S *msg;
+ int rc = 0;
+
+ buffer = kmalloc(sizeof(struct SmsMsgData_S) +
+ SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
+ if (!buffer) {
+ sms_err("Could not allocate buffer for "
+ "init device message.");
+ return -ENOMEM;
+ }
+
+ msg = (struct SmsMsgData_S *)SMS_ALIGN_ADDRESS(buffer);
+ SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ,
+ sizeof(struct SmsMsgData_S));
+ msg->msgData[0] = mode;
+
+ smsendian_handle_tx_message((struct SmsMsgHdr_S *)msg);
+ rc = smscore_sendrequest_and_wait(coredev, msg,
+ msg->xMsgHeader. msgLength,
+ &coredev->init_device_done);
+
+ kfree(buffer);
+ return rc;
}
/**
@@ -838,13 +1118,11 @@ static inline char *sms_get_fw_name(struct
smscore_device_t *coredev,
*/
int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
{
- void *buffer;
int rc = 0;
- enum sms_device_type_st type;
sms_debug("set device mode to %d", mode);
if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
- if (mode < SMSHOSTLIB_DEVMD_DVBT || mode >=
SMSHOSTLIB_DEVMD_RAW_TUNER) {
+ if (mode < SMSHOSTLIB_DEVMD_DVBT || mode >= SMSHOSTLIB_DEVMD_MAX) {
sms_err("invalid mode specified %d", mode);
return -EINVAL;
}
@@ -865,56 +1143,35 @@ int smscore_set_device_mode(struct
smscore_device_t *coredev, int mode)
}
if (!(coredev->modes_supported & (1 << mode))) {
- char *fw_filename;
+ rc = smscore_load_firmware_from_file(coredev, mode, 0, NULL);
- type = smscore_registry_gettype(coredev->devpath);
- fw_filename = sms_get_fw_name(coredev, mode, type);
-
- rc = smscore_load_firmware_from_file(coredev,
- fw_filename, NULL);
+ /*
+ * try again with the default firmware -
+ * get the fw filename from look-up table
+ */
if (rc < 0) {
- sms_debug("error %d loading firmware: %s, "
- "trying again with default firmware",
- rc, fw_filename);
-
- /* try again with the default firmware */
- fw_filename = smscore_fw_lkup[mode][type];
- rc = smscore_load_firmware_from_file(coredev,
- fw_filename, NULL);
+ sms_debug("error %d loading firmware, "
+ "trying again with default firmware", rc);
+ rc = smscore_load_firmware_from_file(coredev, mode, 1, NULL);
+ }
if (rc < 0) {
- sms_debug("error %d loading firmware", rc);
+ sms_debug("error %d loading firmware", rc);
return rc;
}
- }
- sms_log("firmware download success: %s", fw_filename);
- } else
- sms_info("mode %d supported by running "
- "firmware", mode);
- buffer = kmalloc(sizeof(struct SmsMsgData_S) +
- SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
- if (buffer) {
- struct SmsMsgData_S *msg =
- (struct SmsMsgData_S *)
- SMS_ALIGN_ADDRESS(buffer);
-
- SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ,
- sizeof(struct SmsMsgData_S));
- msg->msgData[0] = mode;
-
- rc = smscore_sendrequest_and_wait(
- coredev, msg, msg->xMsgHeader.msgLength,
- &coredev->init_device_done);
-
- kfree(buffer);
+ sms_info("firmware download success");
} else {
- sms_err("Could not allocate buffer for "
- "init device message.");
- rc = -ENOMEM;
+ sms_info("mode %d is already supported by running "
+ "firmware", mode);
+ }
+
+ rc = smscore_init_device(coredev, mode);
+ if (rc < 0) {
+ sms_err("device init failed, rc %d.", rc);
}
} else {
- if (mode < SMSHOSTLIB_DEVMD_DVBT || mode > SMSHOSTLIB_DEVMD_DVBT_BDA)
{
+ if (mode < SMSHOSTLIB_DEVMD_DVBT || mode >= SMSHOSTLIB_DEVMD_MAX) {
sms_err("invalid mode specified %d", mode);
return -EINVAL;
}
@@ -943,6 +1200,58 @@ int smscore_set_device_mode(struct
smscore_device_t *coredev, int mode)
sms_err("return error code %d.", rc);
return rc;
}
+EXPORT_SYMBOL_GPL(smscore_set_device_mode);
+
+/**
+ * configures device features according to voard configuration
structure.
+ *
+ * @param coredev pointer to a coredev object returned by
+ * smscore_register_device
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_configure_board(struct smscore_device_t *coredev) {
+ struct sms_board* board;
+
+ board = sms_get_board(coredev->board_id);
+ if (!board)
+ {
+ sms_err("no board configuration exist.");
+ return -1;
+ }
+
+ if (board->mtu)
+ {
+ struct SmsMsgData_S MtuMsg;
+ sms_debug("set max transmit unit %d", board->mtu);
+
+ MtuMsg.xMsgHeader.msgSrcId = 0;
+ MtuMsg.xMsgHeader.msgDstId = HIF_TASK;
+ MtuMsg.xMsgHeader.msgFlags = 0;
+ MtuMsg.xMsgHeader.msgType = MSG_SMS_SET_MAX_TX_MSG_LEN_REQ;
+ MtuMsg.xMsgHeader.msgLength = sizeof(MtuMsg);
+ MtuMsg.msgData[0] = board->mtu;
+
+ smsendian_handle_tx_message((struct SmsMsgHdr_S *)&MtuMsg);
+ coredev->sendrequest_handler(coredev->context, &MtuMsg,
sizeof(MtuMsg));
+ }
+
+ if (board->crystal)
+ {
+ struct SmsMsgData_S CrysMsg;
+ sms_debug("set crystal value %d", board->crystal);
+
+ SMS_INIT_MSG(&CrysMsg.xMsgHeader,
+ MSG_SMS_NEW_CRYSTAL_REQ,
+ sizeof(CrysMsg));
+ CrysMsg.msgData[0] = board->crystal;
+
+ smsendian_handle_tx_message((struct SmsMsgHdr_S *)&CrysMsg);
+ coredev->sendrequest_handler(coredev->context, &CrysMsg,
sizeof(CrysMsg));
+ }
+
+ return 0;
+}
/**
* calls device handler to get current mode of operation
@@ -1099,6 +1408,13 @@ void smscore_onresponse(struct smscore_device_t
*coredev,
case MSG_SW_RELOAD_EXEC_RES:
sms_debug("MSG_SW_RELOAD_EXEC_RES");
break;
+ case MSG_SMS_DATA_VALIDITY_RES:
+ {
+ struct SmsMsgData_S *validity = (struct SmsMsgData_S *) phdr;
+ sms_err("MSG_SMS_DATA_VALIDITY_RES, checksum = 0x%x",
validity->msgData[0]);
+ complete(&coredev->data_validity_done);
+ break;
+ }
case MSG_SMS_SWDOWNLOAD_TRIGGER_RES:
sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES");
complete(&coredev->trigger_done);
@@ -1188,8 +1504,8 @@ EXPORT_SYMBOL_GPL(smscore_getbuffer);
*/
void smscore_putbuffer(struct smscore_device_t *coredev,
struct smscore_buffer_t *cb) {
- wake_up_interruptible(&coredev->buffer_mng_waitq);
list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock);
+ wake_up_interruptible(&coredev->buffer_mng_waitq);
}
EXPORT_SYMBOL_GPL(smscore_putbuffer);
--
1.7.4.1
^ permalink raw reply related [flat|nested] 2+ messages in thread* Re: [PATCH 12/17]DVB:Siano drivers - Improve firmware load and reload mechanism.
2011-09-20 10:31 [PATCH 12/17]DVB:Siano drivers - Improve firmware load and reload mechanism Doron Cohen
@ 2011-09-23 22:44 ` Mauro Carvalho Chehab
0 siblings, 0 replies; 2+ messages in thread
From: Mauro Carvalho Chehab @ 2011-09-23 22:44 UTC (permalink / raw)
To: doronc; +Cc: linux-media
Em 20-09-2011 07:31, Doron Cohen escreveu:
> Hi,
> This patch step Improve firmware load and reload mechanism in order to
> support new siano devices and match all existing devices.
>
> Thanks,
> Doron Cohen
>
> -----------------------
>
>>From 59062b9fbc2f3c28cbb1ec014c6ed5a3e065a7de Mon Sep 17 00:00:00 2001
> From: Doron Cohen <doronc@siano-ms.com>
> Date: Tue, 20 Sep 2011 08:22:29 +0300
> Subject: [PATCH 16/21] Improve firmware load and reload mechanism in
> order to support new siano devices and match all existing devices.
>
> ---
> drivers/media/dvb/siano/smscoreapi.c | 530
> +++++++++++++++++++++++++++-------
> 1 files changed, 423 insertions(+), 107 deletions(-)
>
> diff --git a/drivers/media/dvb/siano/smscoreapi.c
> b/drivers/media/dvb/siano/smscoreapi.c
> index db24391..e50e356 100644
> --- a/drivers/media/dvb/siano/smscoreapi.c
> +++ b/drivers/media/dvb/siano/smscoreapi.c
> @@ -312,6 +312,7 @@ smscore_buffer_t *smscore_createbuffer(u8 *buffer,
> void *common_buffer,
> cb->p = buffer;
> cb->offset_in_common = buffer - (u8 *) common_buffer;
> cb->phys = common_buffer_phys + cb->offset_in_common;
> + cb->offset=0;
>
> return cb;
> }
> @@ -352,6 +353,7 @@ int smscore_register_device(struct
> smsdevice_params_t *params,
> /* init completion events */
> init_completion(&dev->version_ex_done);
> init_completion(&dev->data_download_done);
> + init_completion(&dev->data_validity_done);
> init_completion(&dev->trigger_done);
> init_completion(&dev->init_device_done);
> init_completion(&dev->reload_start_done);
> @@ -360,6 +362,7 @@ int smscore_register_device(struct
> smsdevice_params_t *params,
> init_completion(&dev->gpio_set_level_done);
> init_completion(&dev->gpio_get_level_done);
> init_completion(&dev->ir_init_done);
> + init_completion(&dev->device_ready_done);
>
> /* Buffer management */
> init_waitqueue_head(&dev->buffer_mng_waitq);
> @@ -426,7 +429,13 @@ EXPORT_SYMBOL_GPL(smscore_register_device);
>
> static int smscore_sendrequest_and_wait(struct smscore_device_t
> *coredev,
> void *buffer, size_t size, struct completion *completion) {
> - int rc = coredev->sendrequest_handler(coredev->context, buffer, size);
> + int rc;
> +
> + if (completion == NULL)
> + return -EINVAL;
> + init_completion(completion);
> +
> + rc = coredev->sendrequest_handler(coredev->context, buffer, size);
> if (rc < 0) {
> sms_info("sendrequest returned error %d", rc);
> return rc;
> @@ -535,7 +544,8 @@ static int smscore_load_firmware_family2(struct
> smscore_device_t *coredev,
> {
> struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer;
> struct SmsMsgHdr_S *msg;
> - u32 mem_address;
> + u32 mem_address, calc_checksum = 0;
> + u32 i, *ptr;
> u8 *payload = firmware->Payload;
> int rc = 0;
> firmware->StartAddress = le32_to_cpu(firmware->StartAddress);
> @@ -563,9 +573,17 @@ static int smscore_load_firmware_family2(struct
> smscore_device_t *coredev,
> rc = smscore_sendrequest_and_wait(coredev, msg,
> msg->msgLength,
> &coredev->reload_start_done);
> +
> + if (rc < 0) {
> + sms_err("device reload failed, rc %d", rc);
> + goto exit_fw_download;
> + }
> +
> mem_address = *(u32 *) &payload[20];
> }
>
> + for (i = 0, ptr = (u32*)firmware->Payload; i < firmware->Length/4 ; i
> ++, ptr++)
> + calc_checksum += *ptr;
> while (size && rc >= 0) {
> struct SmsDataDownload_S *DataMsg =
> (struct SmsDataDownload_S *) msg;
> @@ -578,14 +596,9 @@ static int smscore_load_firmware_family2(struct
> smscore_device_t *coredev,
> DataMsg->MemAddr = mem_address;
> memcpy(DataMsg->Payload, payload, payload_size);
>
> - if ((coredev->device_flags & SMS_ROM_NO_RESPONSE) &&
> - (coredev->mode == SMSHOSTLIB_DEVMD_NONE))
> - rc = coredev->sendrequest_handler(
> - coredev->context, DataMsg,
> - DataMsg->xMsgHeader.msgLength);
> - else
> - rc = smscore_sendrequest_and_wait(
> - coredev, DataMsg,
> +
> +
> + rc = smscore_sendrequest_and_wait(coredev, DataMsg,
> DataMsg->xMsgHeader.msgLength,
> &coredev->data_download_done);
>
> @@ -594,44 +607,63 @@ static int smscore_load_firmware_family2(struct
> smscore_device_t *coredev,
> mem_address += payload_size;
> }
>
> - if (rc >= 0) {
> + if (rc < 0)
> + goto exit_fw_download;
> +
> + sms_err("sending MSG_SMS_DATA_VALIDITY_REQ expecting 0x%x",
> calc_checksum);
> + SMS_INIT_MSG(msg, MSG_SMS_DATA_VALIDITY_REQ,
> + sizeof(struct SmsMsgHdr_S) +
> + sizeof(u32) * 3);
> + ((struct SmsMsgData_S *)msg)->msgData[0] = firmware->StartAddress;
> + /* Entry point */
> + ((struct SmsMsgData_S *)msg)->msgData[1] = firmware->Length;
> + ((struct SmsMsgData_S *)msg)->msgData[2] = 0; /* Regular checksum*/
> + smsendian_handle_tx_message((struct SmsMsgHdr_S *)msg);
> + rc = smscore_sendrequest_and_wait(coredev, msg, ((struct SmsMsgData_S
> *)msg)->xMsgHeader.msgLength, &coredev->data_validity_done);
> + if (rc < 0)
> + goto exit_fw_download;
> +
> +
> if (coredev->mode == SMSHOSTLIB_DEVMD_NONE) {
> struct SmsMsgData_S *TriggerMsg =
> (struct SmsMsgData_S *) msg;
>
> + sms_debug("sending MSG_SMS_SWDOWNLOAD_TRIGGER_REQ");
> SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ,
> sizeof(struct SmsMsgHdr_S) +
> sizeof(u32) * 5);
>
> TriggerMsg->msgData[0] = firmware->StartAddress;
> /* Entry point */
> - TriggerMsg->msgData[1] = 5; /* Priority */
> + TriggerMsg->msgData[1] = 6; /* Priority */
> TriggerMsg->msgData[2] = 0x200; /* Stack size */
> TriggerMsg->msgData[3] = 0; /* Parameter */
> TriggerMsg->msgData[4] = 4; /* Task ID */
>
> - if (coredev->device_flags & SMS_ROM_NO_RESPONSE) {
> - rc = coredev->sendrequest_handler(
> - coredev->context, TriggerMsg,
> - TriggerMsg->xMsgHeader.msgLength);
> - msleep(100);
> - } else
> - rc = smscore_sendrequest_and_wait(
> - coredev, TriggerMsg,
> + smsendian_handle_tx_message((struct SmsMsgHdr_S *)msg);
> + rc = smscore_sendrequest_and_wait(coredev,
> + TriggerMsg,
> TriggerMsg->xMsgHeader.msgLength,
> &coredev->trigger_done);
> } else {
> SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ,
> sizeof(struct SmsMsgHdr_S));
> -
> - rc = coredev->sendrequest_handler(coredev->context,
> - msg, msg->msgLength);
> - }
> - msleep(500);
> + smsendian_handle_tx_message((struct SmsMsgHdr_S *)msg);
> + rc = coredev->sendrequest_handler(coredev->context, msg,
> + msg->msgLength);
> }
>
> - sms_debug("rc=%d, postload=%p ", rc,
> - coredev->postload_handler);
> + if (rc < 0)
> + goto exit_fw_download;
> +
> + /*
> + * backward compatibility - wait to device_ready_done for
> + * not more than 400 ms
> + */
> + msleep(400);
> +
> +exit_fw_download:
> + sms_debug("rc=%d, postload=0x%p ", rc, coredev->postload_handler);
>
> kfree(msg);
>
> @@ -653,42 +685,211 @@ static int smscore_load_firmware_family2(struct
> smscore_device_t *coredev,
> * @return 0 on success, <0 on error.
> */
> static int smscore_load_firmware_from_file(struct smscore_device_t
> *coredev,
> - char *filename,
> - loadfirmware_t loadfirmware_handler)
> -{
> + int mode, int lookup, loadfirmware_t loadfirmware_handler) {
> int rc = -ENOENT;
> + u8 *fw_buf;
> + u32 fw_buf_size;
> +
> +#ifdef REQUEST_FIRMWARE_SUPPORTED
NACK. request_firmware should always be there for devices that have firmware.
> const struct firmware *fw;
> - u8 *fw_buffer;
>
> - if (loadfirmware_handler == NULL && !(coredev->device_flags &
> - SMS_DEVICE_FAMILY2))
> + char* fw_filename = smscore_get_fw_filename(coredev, mode, lookup);
> + if (!strcmp(fw_filename,"none"))
> + return -ENOENT;
> +
> + if (loadfirmware_handler == NULL && !(coredev->device_flags
> + & SMS_DEVICE_FAMILY2))
> return -EINVAL;
>
> - rc = request_firmware(&fw, filename, coredev->device);
> + rc = request_firmware(&fw, fw_filename, coredev->device);
> if (rc < 0) {
> - sms_info("failed to open \"%s\"", filename);
> + sms_info("failed to open \"%s\"", fw_filename);
> return rc;
> }
> - sms_info("read FW %s, size=%zd", filename, fw->size);
> - fw_buffer = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT),
> + sms_info("read fw %s, buffer size=0x%x", fw_filename, fw->size);
> + fw_buf = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT),
> GFP_KERNEL | GFP_DMA);
> - if (fw_buffer) {
> - memcpy(fw_buffer, fw->data, fw->size);
> + if (!fw_buf) {
> + sms_info("failed to allocate firmware buffer");
> + return -ENOMEM;
> + }
> + memcpy(fw_buf, fw->data, fw->size);
> + fw_buf_size = fw->size;
> +#else
> + if (!coredev->fw_buf) {
> + sms_info("missing fw file buffer");
> + return -EINVAL;
> + }
> + fw_buf = coredev->fw_buf;
> + fw_buf_size = coredev->fw_buf_size;
> +#endif
>
> rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ?
> - smscore_load_firmware_family2(coredev,
> - fw_buffer,
> - fw->size) :
> - loadfirmware_handler(coredev->context,
> - fw_buffer, fw->size);
> + smscore_load_firmware_family2(coredev, fw_buf, fw_buf_size)
> + : loadfirmware_handler(coredev->context, fw_buf,
> + fw_buf_size);
> +
> + kfree(fw_buf);
> +
> +#ifdef REQUEST_FIRMWARE_SUPPORTED
> + release_firmware(fw);
> +#else
> + coredev->fw_buf = NULL;
> + coredev->fw_buf_size = 0;
> +#endif
> + return rc;
> +}
> +
> +/**
> + * Send chunk of firmware data using SMS MSGs
> + * The motivation is to eliminate the need of big memory allocation in
> kernel for firmware
> + * download.
> + *
> + * @param coredev pointer to a coredev object returned by
> + * smscore_register_device
> + * @param buffer pointer to a buffer
> + * @param size size of buffer
> + *
> + * @return 0 on success, <0 on error.
> + */
> +int smscore_send_fw_chunk(struct smscore_device_t *coredev,
> + void *buffer, size_t size)
> +{
> +
> + struct SmsMsgHdr_S *msg;
> + int rc = 0;
> + int offset = 0;
> +
> + if (buffer == NULL)
> + {
> + sms_debug("Error: NULL buffer");
> + return -1;
> + }
> +
> + /* First chunk */
> + if (coredev->start_address == 0)
> + {
> + struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer;
> + coredev->start_address = le32_to_cpu(firmware->StartAddress);
> + coredev->current_address = coredev->start_address;
> + offset = 12;
> + size -= 12;
> +
> + if (coredev->preload_handler)
> + {
> + rc = coredev->preload_handler(coredev->context);
> + if (rc < 0)
> + return rc;
> + }
> + }
> +
> + /* PAGE_SIZE buffer shall be enough and dma aligned */
> + msg = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
> + if (!msg)
> + return -ENOMEM;
> +
> + while (size && rc >= 0) {
> + int payload_size;
> + struct SmsDataDownload_S *DataMsg;
> + sms_debug("sending MSG_SMS_DATA_DOWNLOAD_REQ");
> + DataMsg = (struct SmsDataDownload_S *) msg;
> + payload_size = min((int)size, SMS_MAX_PAYLOAD_SIZE);
>
> - kfree(fw_buffer);
> + SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ,
> + (u16) (sizeof(struct SmsMsgHdr_S) +
> + sizeof(u32) + payload_size));
> +
> + DataMsg->MemAddr = coredev->current_address;
> + copy_from_user(DataMsg->Payload, (u8*)(buffer + offset),
> payload_size);
> +
> + smsendian_handle_tx_message((struct SmsMsgHdr_S *)msg);
> + rc = smscore_sendrequest_and_wait(coredev, DataMsg,
> + DataMsg->xMsgHeader.msgLength,
> + &coredev->data_download_done);
> +
> + size -= payload_size;
> + offset += payload_size;
> + coredev->current_address += payload_size;
> + }
> +
> + kfree(msg);
> +
> + return rc;
> +}
> +EXPORT_SYMBOL_GPL(smscore_send_fw_chunk);
> +
> +
> +/**
> + * Send last chunk of firmware data using SMS MSGs
> + *
> + * @param coredev pointer to a coredev object returned by
> + * smscore_register_device
> + * @param buffer pointer to a buffer
> + * @param size size of buffer
> + *
> + * @return 0 on success, <0 on error.
> + */
> +int smscore_send_last_fw_chunk(struct smscore_device_t *coredev,
> + void *buffer, size_t size)
> +{
> + int rc = 0;
> + struct SmsMsgHdr_S *msg;
> +
> + rc = smscore_send_fw_chunk(coredev, buffer, size);
> + if (rc < 0)
> + return rc;
> +
> + /* PAGE_SIZE buffer shall be enough and dma aligned */
> + msg = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
> + if (!msg)
> + return -ENOMEM;
> +
> + if (coredev->mode == SMSHOSTLIB_DEVMD_NONE) {
> + struct SmsMsgData_S *TriggerMsg =
> + (struct SmsMsgData_S *) msg;
> +
> + sms_debug("sending MSG_SMS_SWDOWNLOAD_TRIGGER_REQ");
> + SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ,
> + sizeof(struct SmsMsgHdr_S) +
> + sizeof(u32) * 5);
> +
> + TriggerMsg->msgData[0] = coredev->start_address;
> + /* Entry point */
> + TriggerMsg->msgData[1] = 6; /* Priority */
> + TriggerMsg->msgData[2] = 0x200; /* Stack size */
> + TriggerMsg->msgData[3] = 0; /* Parameter */
> + TriggerMsg->msgData[4] = 4; /* Task ID */
> +
> + smsendian_handle_tx_message((struct SmsMsgHdr_S *)msg);
> + rc = smscore_sendrequest_and_wait(coredev,
> + TriggerMsg,
> + TriggerMsg->xMsgHeader.msgLength,
> + &coredev->trigger_done);
> } else {
> - sms_info("failed to allocate firmware buffer");
> - rc = -ENOMEM;
> + SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ,
> + sizeof(struct SmsMsgHdr_S));
> + smsendian_handle_tx_message((struct SmsMsgHdr_S *)msg);
> + rc = coredev->sendrequest_handler(coredev->context, msg,
> + msg->msgLength);
> }
>
> - release_firmware(fw);
> + /* clear start_address */
> + coredev->start_address = 0;
> +
> + if (rc < 0)
> + goto exit_fw_download;
> +
> + /*
> + * backward compatibility - wait to device_ready_done for
> + * not more than 400 ms
> + */
> + wait_for_completion_timeout(&coredev->device_ready_done,
> + msecs_to_jiffies(400));
> +
> +exit_fw_download:
> + sms_debug("rc=%d, postload=0x%p ", rc, coredev->postload_handler);
> +
> + kfree(msg);
>
> return rc;
> }
> @@ -712,6 +913,7 @@ void smscore_unregister_device(struct
> smscore_device_t *coredev)
>
> /* Release input device (IR) resources */
> #ifdef SMS_RC_SUPPORT_SUBSYS
> + /* Release input device (IR) resources */
> sms_ir_exit(coredev);
> #endif /*SMS_RC_SUPPORT_SUBSYS*/
> smscore_notify_clients(coredev);
> @@ -737,7 +939,9 @@ void smscore_unregister_device(struct
> smscore_device_t *coredev)
>
> sms_info("waiting for %d buffer(s)",
> coredev->num_buffers - num_buffers);
> + kmutex_unlock(&g_smscore_deviceslock);
kmutex_unlock??? Don't re-define a function that already exists at the
Linux Kernel.
> msleep(100);
> + kmutex_lock(&g_smscore_deviceslock);
> }
>
> sms_info("freed %d buffers", num_buffers);
> @@ -800,30 +1004,106 @@ static int smscore_detect_mode(struct
> smscore_device_t *coredev)
> }
>
> static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = {
> - /*Stellar NOVA A0 Nova B0 VEGA*/
> +/*Stellar, NOVA A0, Nova B0, VEGA, VENICE, MING, PELE, RIO,
> DENVER_1530, DENVER_2160*/
> /*DVBT*/
> - {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
> +{ "none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none",
> "none", "none", "none", "dvb_rio.inp", "none", "none" },
> /*DVBH*/
> - {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
> +{ "none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none",
> "none", "none", "none", "dvbh_rio.inp", "none", "none" },
> /*TDMB*/
> - {"none", "tdmb_nova_12mhz.inp", "tdmb_nova_12mhz_b0.inp", "none"},
> +{ "none", "tdmb_nova_12mhz.inp", "tdmb_nova_12mhz_b0.inp", "none",
> "none", "none", "none", "none", "none", "tdmb_denver.inp" },
> /*DABIP*/
> - {"none", "none", "none", "none"},
> - /*BDA*/
> - {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
> +{ "none", "none", "none", "none", "none", "none", "none", "none",
> "none", "none" },
> +/*DVBT_BDA*/
> +{ "none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none",
> "none", "none", "none", "dvb_rio.inp", "none", "none" },
> /*ISDBT*/
> - {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
> - /*ISDBTBDA*/
> - {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
> +{ "none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none",
> "none", "none", "isdbt_pele.inp", "isdbt_rio.inp", "none", "none" },
> +/*ISDBT_BDA*/
> +{ "none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none",
> "none", "none", "isdbt_pele.inp", "isdbt_rio.inp", "none", "none" },
> /*CMMB*/
> - {"none", "none", "none", "cmmb_vega_12mhz.inp"}
> +{ "none", "none", "none", "cmmb_vega_12mhz.inp",
> "cmmb_venice_12mhz.inp", "cmmb_ming_app.inp", "none", "none", "none",
> "none" },
> +/*RAW - not supported*/
> +{ "none", "none", "none", "none", "none", "none", "none", "none",
> "none", "none" },
> +/*FM*/
> +{ "none", "none", "fm_radio.inp", "none", "none", "none", "none",
> "fm_radio_rio.inp", "none", "none" },
> +/*FM_BDA*/
> +{ "none", "none", "fm_radio.inp", "none", "none", "none", "none",
> "fm_radio_rio.inp", "none", "none" },
> +/*ATSC*/
> +{ "none", "none", "none", "none", "none", "none", "none", "none",
> "atsc_denver.inp", "none" }
> };
>
> -static inline char *sms_get_fw_name(struct smscore_device_t *coredev,
> - int mode, enum sms_device_type_st type)
> +/**
> + * get firmware file name from one of the two mechanisms : sms_boards
> or
> + * smscore_fw_lkup.
> +
> + * @param coredev pointer to a coredev object returned by
> + * smscore_register_device
> + * @param mode requested mode of operation
> + * @param lookup if 1, always get the fw filename from smscore_fw_lkup
> + * table. if 0, try first to get from sms_boards
> + *
> + * @return 0 on success, <0 on error.
> + */
> +char *smscore_get_fw_filename(struct smscore_device_t *coredev, int
> mode, int lookup) {
> + char **fw;
> + int board_id = smscore_get_board_id(coredev);
> + enum sms_device_type_st type =
> smscore_registry_gettype(coredev->devpath);
> +
> + if ( (board_id == SMS_BOARD_UNKNOWN) ||
> + (lookup == 1) ) {
> + sms_debug("trying to get fw name from lookup table mode %d type %d",
> mode, type);
> + return smscore_fw_lkup[mode][type];
> + }
> +
> + sms_debug("trying to get fw name from sms_boards board_id %d mode %d",
> board_id, mode);
> + fw = sms_get_board(board_id)->fw;
> + if (fw == NULL) {
> + sms_debug("cannot find fw name in sms_boards, getting from lookup
> table mode %d type %d", mode, type);
> + return smscore_fw_lkup[mode][type];
> + }
> +
> + if (fw[mode] == NULL) {
> + sms_debug("cannot find fw name in sms_boards, getting from lookup
> table mode %d type %d", mode, type);
> + return smscore_fw_lkup[mode][type];
> + }
> +
> + return fw[mode];
> +}
> +
> +/**
> + * send init device request and wait for response
> + *
> + * @param coredev pointer to a coredev object returned by
> + * smscore_register_device
> + * @param mode requested mode of operation
> + *
> + * @return 0 on success, <0 on error.
> + */
> +int smscore_init_device(struct smscore_device_t *coredev, int mode)
> {
> - char **fw = sms_get_board(smscore_get_board_id(coredev))->fw;
> - return (fw && fw[mode]) ? fw[mode] : smscore_fw_lkup[mode][type];
> + void* buffer;
> + struct SmsMsgData_S *msg;
> + int rc = 0;
> +
> + buffer = kmalloc(sizeof(struct SmsMsgData_S) +
> + SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
> + if (!buffer) {
> + sms_err("Could not allocate buffer for "
> + "init device message.");
> + return -ENOMEM;
> + }
> +
> + msg = (struct SmsMsgData_S *)SMS_ALIGN_ADDRESS(buffer);
> + SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ,
> + sizeof(struct SmsMsgData_S));
> + msg->msgData[0] = mode;
> +
> + smsendian_handle_tx_message((struct SmsMsgHdr_S *)msg);
> + rc = smscore_sendrequest_and_wait(coredev, msg,
> + msg->xMsgHeader. msgLength,
> + &coredev->init_device_done);
> +
> + kfree(buffer);
> + return rc;
> }
>
> /**
> @@ -838,13 +1118,11 @@ static inline char *sms_get_fw_name(struct
> smscore_device_t *coredev,
> */
> int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
> {
> - void *buffer;
> int rc = 0;
> - enum sms_device_type_st type;
>
> sms_debug("set device mode to %d", mode);
> if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
> - if (mode < SMSHOSTLIB_DEVMD_DVBT || mode >=
> SMSHOSTLIB_DEVMD_RAW_TUNER) {
> + if (mode < SMSHOSTLIB_DEVMD_DVBT || mode >= SMSHOSTLIB_DEVMD_MAX) {
> sms_err("invalid mode specified %d", mode);
> return -EINVAL;
> }
> @@ -865,56 +1143,35 @@ int smscore_set_device_mode(struct
> smscore_device_t *coredev, int mode)
> }
>
> if (!(coredev->modes_supported & (1 << mode))) {
> - char *fw_filename;
> + rc = smscore_load_firmware_from_file(coredev, mode, 0, NULL);
>
> - type = smscore_registry_gettype(coredev->devpath);
> - fw_filename = sms_get_fw_name(coredev, mode, type);
> -
> - rc = smscore_load_firmware_from_file(coredev,
> - fw_filename, NULL);
> + /*
> + * try again with the default firmware -
> + * get the fw filename from look-up table
> + */
> if (rc < 0) {
> - sms_debug("error %d loading firmware: %s, "
> - "trying again with default firmware",
> - rc, fw_filename);
> -
> - /* try again with the default firmware */
> - fw_filename = smscore_fw_lkup[mode][type];
> - rc = smscore_load_firmware_from_file(coredev,
> - fw_filename, NULL);
> + sms_debug("error %d loading firmware, "
> + "trying again with default firmware", rc);
> + rc = smscore_load_firmware_from_file(coredev, mode, 1, NULL);
> + }
>
> if (rc < 0) {
> - sms_debug("error %d loading firmware", rc);
> + sms_debug("error %d loading firmware", rc);
> return rc;
> }
> - }
> - sms_log("firmware download success: %s", fw_filename);
> - } else
> - sms_info("mode %d supported by running "
> - "firmware", mode);
>
> - buffer = kmalloc(sizeof(struct SmsMsgData_S) +
> - SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
> - if (buffer) {
> - struct SmsMsgData_S *msg =
> - (struct SmsMsgData_S *)
> - SMS_ALIGN_ADDRESS(buffer);
> -
> - SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ,
> - sizeof(struct SmsMsgData_S));
> - msg->msgData[0] = mode;
> -
> - rc = smscore_sendrequest_and_wait(
> - coredev, msg, msg->xMsgHeader.msgLength,
> - &coredev->init_device_done);
> -
> - kfree(buffer);
> + sms_info("firmware download success");
> } else {
> - sms_err("Could not allocate buffer for "
> - "init device message.");
> - rc = -ENOMEM;
> + sms_info("mode %d is already supported by running "
> + "firmware", mode);
> + }
> +
> + rc = smscore_init_device(coredev, mode);
> + if (rc < 0) {
> + sms_err("device init failed, rc %d.", rc);
> }
> } else {
> - if (mode < SMSHOSTLIB_DEVMD_DVBT || mode > SMSHOSTLIB_DEVMD_DVBT_BDA)
> {
> + if (mode < SMSHOSTLIB_DEVMD_DVBT || mode >= SMSHOSTLIB_DEVMD_MAX) {
> sms_err("invalid mode specified %d", mode);
> return -EINVAL;
> }
> @@ -943,6 +1200,58 @@ int smscore_set_device_mode(struct
> smscore_device_t *coredev, int mode)
> sms_err("return error code %d.", rc);
> return rc;
> }
> +EXPORT_SYMBOL_GPL(smscore_set_device_mode);
> +
> +/**
> + * configures device features according to voard configuration
> structure.
> + *
> + * @param coredev pointer to a coredev object returned by
> + * smscore_register_device
> + *
> + * @return 0 on success, <0 on error.
> + */
> +int smscore_configure_board(struct smscore_device_t *coredev) {
> + struct sms_board* board;
> +
> + board = sms_get_board(coredev->board_id);
> + if (!board)
> + {
> + sms_err("no board configuration exist.");
> + return -1;
> + }
> +
> + if (board->mtu)
> + {
> + struct SmsMsgData_S MtuMsg;
> + sms_debug("set max transmit unit %d", board->mtu);
> +
> + MtuMsg.xMsgHeader.msgSrcId = 0;
> + MtuMsg.xMsgHeader.msgDstId = HIF_TASK;
> + MtuMsg.xMsgHeader.msgFlags = 0;
> + MtuMsg.xMsgHeader.msgType = MSG_SMS_SET_MAX_TX_MSG_LEN_REQ;
> + MtuMsg.xMsgHeader.msgLength = sizeof(MtuMsg);
> + MtuMsg.msgData[0] = board->mtu;
> +
> + smsendian_handle_tx_message((struct SmsMsgHdr_S *)&MtuMsg);
> + coredev->sendrequest_handler(coredev->context, &MtuMsg,
> sizeof(MtuMsg));
> + }
> +
> + if (board->crystal)
> + {
> + struct SmsMsgData_S CrysMsg;
> + sms_debug("set crystal value %d", board->crystal);
> +
> + SMS_INIT_MSG(&CrysMsg.xMsgHeader,
> + MSG_SMS_NEW_CRYSTAL_REQ,
> + sizeof(CrysMsg));
> + CrysMsg.msgData[0] = board->crystal;
> +
> + smsendian_handle_tx_message((struct SmsMsgHdr_S *)&CrysMsg);
> + coredev->sendrequest_handler(coredev->context, &CrysMsg,
> sizeof(CrysMsg));
> + }
> +
> + return 0;
> +}
>
> /**
> * calls device handler to get current mode of operation
> @@ -1099,6 +1408,13 @@ void smscore_onresponse(struct smscore_device_t
> *coredev,
> case MSG_SW_RELOAD_EXEC_RES:
> sms_debug("MSG_SW_RELOAD_EXEC_RES");
> break;
> + case MSG_SMS_DATA_VALIDITY_RES:
> + {
> + struct SmsMsgData_S *validity = (struct SmsMsgData_S *) phdr;
> + sms_err("MSG_SMS_DATA_VALIDITY_RES, checksum = 0x%x",
> validity->msgData[0]);
> + complete(&coredev->data_validity_done);
> + break;
> + }
> case MSG_SMS_SWDOWNLOAD_TRIGGER_RES:
> sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES");
> complete(&coredev->trigger_done);
> @@ -1188,8 +1504,8 @@ EXPORT_SYMBOL_GPL(smscore_getbuffer);
> */
> void smscore_putbuffer(struct smscore_device_t *coredev,
> struct smscore_buffer_t *cb) {
> - wake_up_interruptible(&coredev->buffer_mng_waitq);
> list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock);
> + wake_up_interruptible(&coredev->buffer_mng_waitq);
> }
> EXPORT_SYMBOL_GPL(smscore_putbuffer);
>
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2011-09-23 22:44 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-09-20 10:31 [PATCH 12/17]DVB:Siano drivers - Improve firmware load and reload mechanism Doron Cohen
2011-09-23 22:44 ` Mauro Carvalho Chehab
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).