diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-03-06 12:15:08 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-03-21 07:40:05 -0300 |
commit | 018b0c6f8acb5819591f3b43b51fc342af548c82 (patch) | |
tree | a5831567bc09f0117c2aca5a32dc4043a16d5921 | |
parent | 7333839505d568e0e69a6d02a3ee0f455b6c37a5 (diff) | |
download | linux-018b0c6f8acb5819591f3b43b51fc342af548c82.tar.bz2 |
[media] siano: make load firmware logic to work with newer firmwares
There are new firmwares for sms2xxx devices. Change the firmware
load logic to handle those newer firmwares and devices.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | drivers/media/common/siano/smscoreapi.c | 348 | ||||
-rw-r--r-- | drivers/media/common/siano/smscoreapi.h | 8 |
2 files changed, 220 insertions, 136 deletions
diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 7b5d81a30cdf..d489701c3842 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -683,6 +683,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); @@ -753,7 +754,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; @@ -850,8 +857,9 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev, void *buffer, size_t size) { struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer; - struct SmsMsgHdr_ST *msg; - u32 mem_address; + struct SmsMsgData_ST4 *msg; + u32 mem_address, calc_checksum = 0; + u32 i, *ptr; u8 *payload = firmware->Payload; int rc = 0; firmware->StartAddress = le32_to_cpu(firmware->StartAddress); @@ -874,34 +882,35 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev, if (coredev->mode != DEVICE_MODE_NONE) { sms_debug("sending reload command."); - SMS_INIT_MSG(msg, MSG_SW_RELOAD_START_REQ, + SMS_INIT_MSG(&msg->xMsgHeader, MSG_SW_RELOAD_START_REQ, sizeof(struct SmsMsgHdr_ST)); rc = smscore_sendrequest_and_wait(coredev, msg, - msg->msgLength, + msg->xMsgHeader.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_ST *DataMsg = (struct SmsDataDownload_ST *) msg; int payload_size = min((int) size, SMS_MAX_PAYLOAD_SIZE); - SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ, + SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_DATA_DOWNLOAD_REQ, (u16)(sizeof(struct SmsMsgHdr_ST) + sizeof(u32) + payload_size)); DataMsg->MemAddr = mem_address; memcpy(DataMsg->Payload, payload, payload_size); - if ((coredev->device_flags & SMS_ROM_NO_RESPONSE) && - (coredev->mode == DEVICE_MODE_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); @@ -910,44 +919,65 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev, mem_address += payload_size; } - if (rc >= 0) { - if (coredev->mode == DEVICE_MODE_NONE) { - struct SmsMsgData_ST *TriggerMsg = - (struct SmsMsgData_ST *) msg; - - SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ, - sizeof(struct SmsMsgHdr_ST) + - sizeof(u32) * 5); - - TriggerMsg->msgData[0] = firmware->StartAddress; - /* Entry point */ - TriggerMsg->msgData[1] = 5; /* 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, + if (rc < 0) + goto exit_fw_download; + + sms_err("sending MSG_SMS_DATA_VALIDITY_REQ expecting 0x%x", + calc_checksum); + SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_DATA_VALIDITY_REQ, + sizeof(msg->xMsgHeader) + + sizeof(u32) * 3); + msg->msgData[0] = firmware->StartAddress; + /* Entry point */ + msg->msgData[1] = firmware->Length; + msg->msgData[2] = 0; /* Regular checksum*/ + smsendian_handle_tx_message(msg); + rc = smscore_sendrequest_and_wait(coredev, msg, + msg->xMsgHeader.msgLength, + &coredev->data_validity_done); + if (rc < 0) + goto exit_fw_download; + + if (coredev->mode == DEVICE_MODE_NONE) { + struct SmsMsgData_ST *TriggerMsg = + (struct SmsMsgData_ST *) msg; + + sms_debug("sending MSG_SMS_SWDOWNLOAD_TRIGGER_REQ"); + SMS_INIT_MSG(&msg->xMsgHeader, + MSG_SMS_SWDOWNLOAD_TRIGGER_REQ, + sizeof(struct SmsMsgHdr_ST) + + sizeof(u32) * 5); + + TriggerMsg->msgData[0] = firmware->StartAddress; + /* 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_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ, - sizeof(struct SmsMsgHdr_ST)); - - rc = coredev->sendrequest_handler(coredev->context, - msg, msg->msgLength); - } - msleep(500); + } else { + SMS_INIT_MSG(&msg->xMsgHeader, MSG_SW_RELOAD_EXEC_REQ, + sizeof(struct SmsMsgHdr_ST)); + smsendian_handle_tx_message((struct SmsMsgHdr_S *)msg); + rc = coredev->sendrequest_handler(coredev->context, msg, + msg->xMsgHeader.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); @@ -956,6 +986,10 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev, rc; } + +static char *smscore_get_fw_filename(struct smscore_device_t *coredev, + int mode, int lookup); + /** * loads specified firmware into a buffer and calls device loadfirmware_handler * @@ -967,41 +1001,43 @@ 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, + int mode, int lookup, loadfirmware_t loadfirmware_handler) { int rc = -ENOENT; + u8 *fw_buf; + u32 fw_buf_size; 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), - GFP_KERNEL | GFP_DMA); - if (fw_buffer) { - memcpy(fw_buffer, fw->data, fw->size); - - rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ? - smscore_load_firmware_family2(coredev, - fw_buffer, - fw->size) : - loadfirmware_handler(coredev->context, - fw_buffer, fw->size); - - kfree(fw_buffer); - } else { + sms_info("read fw %s, buffer size=0x%zx", fw_filename, fw->size); + fw_buf = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT), + GFP_KERNEL | GFP_DMA); + if (!fw_buf) { sms_info("failed to allocate firmware buffer"); - rc = -ENOMEM; + return -ENOMEM; } + memcpy(fw_buf, fw->data, fw->size); + fw_buf_size = fw->size; + + rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ? + smscore_load_firmware_family2(coredev, fw_buf, fw_buf_size) + : loadfirmware_handler(coredev->context, fw_buf, + fw_buf_size); + kfree(fw_buf); release_firmware(fw); return rc; @@ -1050,7 +1086,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); @@ -1107,30 +1145,73 @@ 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*/ - /*DVBT*/ - {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"}, - /*DVBH*/ - {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"}, - /*TDMB*/ - {"none", "tdmb_nova_12mhz.inp", "tdmb_nova_12mhz_b0.inp", "none"}, - /*DABIP*/ - {"none", "none", "none", "none"}, - /*BDA*/ - {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "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"}, - /*CMMB*/ - {"none", "none", "none", "cmmb_vega_12mhz.inp"} + /*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", "none", "none", "dvb_rio.inp", "none", "none" }, + /*DVBH*/ + { "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", "none", "none", "none", "none", "tdmb_denver.inp" }, + /*DABIP*/ + { "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", "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", "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. + */ +static char *smscore_get_fw_filename(struct smscore_device_t *coredev, + int mode, int lookup) { - char **fw = sms_get_board(smscore_get_board_id(coredev))->fw; - return (fw && fw[mode]) ? fw[mode] : smscore_fw_lkup[mode][type]; + 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]; } /** @@ -1145,9 +1226,7 @@ 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) { @@ -1172,55 +1251,30 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode) } if (!(coredev->modes_supported & (1 << mode))) { - char *fw_filename; - - 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); - if (rc < 0) { - sms_warn("error %d loading firmware: %s, " - "trying again with default firmware", - rc, fw_filename); + mode, 0, NULL); - /* try again with the default firmware */ - fw_filename = smscore_fw_lkup[mode][type]; + /* + * try again with the default firmware - + * get the fw filename from look-up table + */ + if (rc < 0) { + sms_debug("error %d loading firmware, trying again with default firmware", + rc); rc = smscore_load_firmware_from_file(coredev, - fw_filename, NULL); - + mode, 1, + NULL); if (rc < 0) { - sms_warn("error %d loading " - "firmware: %s", rc, - fw_filename); + 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_ST) + - SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); - if (buffer) { - struct SmsMsgData_ST *msg = - (struct SmsMsgData_ST *) - SMS_ALIGN_ADDRESS(buffer); - - SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ, - sizeof(struct SmsMsgData_ST)); - msg->msgData[0] = mode; - - rc = smscore_sendrequest_and_wait( - coredev, msg, msg->xMsgHeader.msgLength, - &coredev->init_device_done); - - kfree(buffer); + if (rc >= 0) + 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); } } else { if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) { @@ -1239,8 +1293,25 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode) } if (rc >= 0) { + char *buffer; coredev->mode = mode; coredev->device_flags &= ~SMS_DEVICE_NOT_READY; + + buffer = kmalloc(sizeof(struct SmsMsgData_ST) + + SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); + if (buffer) { + struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *) SMS_ALIGN_ADDRESS(buffer); + + SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ, + sizeof(struct SmsMsgData_ST)); + msg->msgData[0] = mode; + + rc = smscore_sendrequest_and_wait( + coredev, msg, msg->xMsgHeader.msgLength, + &coredev->init_device_done); + + kfree(buffer); + } } if (rc < 0) @@ -1371,6 +1442,15 @@ void smscore_onresponse(struct smscore_device_t *coredev, case MSG_SW_RELOAD_START_RES: complete(&coredev->reload_start_done); break; + case MSG_SMS_DATA_VALIDITY_RES: + { + struct SmsMsgData_ST *validity = (struct SmsMsgData_ST *) phdr; + + sms_err("MSG_SMS_DATA_VALIDITY_RES, checksum = 0x%x", + validity->msgData[0]); + complete(&coredev->data_validity_done); + break; + } case MSG_SMS_DATA_DOWNLOAD_RES: complete(&coredev->data_download_done); break; diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h index f1440a55cb4d..91db8536c2b0 100644 --- a/drivers/media/common/siano/smscoreapi.h +++ b/drivers/media/common/siano/smscoreapi.h @@ -162,6 +162,7 @@ struct smscore_device_t { /* host <--> device messages */ struct completion version_ex_done, data_download_done, trigger_done; + struct completion data_validity_done, device_ready_done; struct completion init_device_done, reload_start_done, resume_done; struct completion gpio_configuration_done, gpio_set_level_done; struct completion gpio_get_level_done, ir_init_done; @@ -594,6 +595,11 @@ struct SmsMsgData_ST2 { u32 msgData[2]; }; +struct SmsMsgData_ST4 { + struct SmsMsgHdr_ST xMsgHeader; + u32 msgData[4]; +}; + struct SmsDataDownload_ST { struct SmsMsgHdr_ST xMsgHeader; u32 MemAddr; @@ -998,8 +1004,6 @@ extern void smscore_onresponse(struct smscore_device_t *coredev, extern int smscore_get_common_buffer_size(struct smscore_device_t *coredev); extern int smscore_map_common_buffer(struct smscore_device_t *coredev, struct vm_area_struct *vma); -extern int smscore_get_fw_filename(struct smscore_device_t *coredev, - int mode, char *filename); extern int smscore_send_fw_file(struct smscore_device_t *coredev, u8 *ufwbuf, int size); |