📄 smscoreapi.c
字号:
coredev, smscore_registry_getmode(coredev->devpath)); if (rc < 0) { sms_info("set device mode faile , rc %d", rc); return rc; } kmutex_lock(&g_smscore_deviceslock); rc = smscore_notify_callbacks(coredev, coredev->device, 1); sms_info("device %p started, rc %d", coredev, rc); kmutex_unlock(&g_smscore_deviceslock); return rc;}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); if (rc < 0) { sms_info("sendrequest returned error %d", rc); return rc; } return wait_for_completion_timeout(completion, msecs_to_jiffies(10000)) ? 0 : -ETIME;}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 = firmware->StartAddress; u8 *payload = firmware->Payload; int rc = 0; sms_info("loading FW to addr 0x%x size %d", mem_address, firmware->Length); 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; if (coredev->mode != DEVICE_MODE_NONE) { sms_debug("sending reload command."); SMS_INIT_MSG(msg, MSG_SW_RELOAD_START_REQ, sizeof(struct SmsMsgHdr_ST)); rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength, &coredev->reload_start_done); mem_address = *(u32 *) &payload[20]; } 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, (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, DataMsg->xMsgHeader.msgLength, &coredev->data_download_done); payload += payload_size; size -= payload_size; 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, 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); } sms_debug("rc=%d, postload=%p ", rc, coredev->postload_handler); kfree(msg); return ((rc >= 0) && coredev->postload_handler) ? coredev->postload_handler(coredev->context) : rc;}/** * loads specified firmware into a buffer and calls device loadfirmware_handler * * @param coredev pointer to a coredev object returned by * smscore_register_device * @param filename null-terminated string specifies firmware file name * @param loadfirmware_handler device handler that loads firmware * * @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 rc = -ENOENT; const struct firmware *fw; u8 *fw_buffer; if (loadfirmware_handler == NULL && !(coredev->device_flags & SMS_DEVICE_FAMILY2)) return -EINVAL; rc = request_firmware(&fw, filename, coredev->device); if (rc < 0) { sms_info("failed to open \"%s\"", 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("failed to allocate firmware buffer"); rc = -ENOMEM; } release_firmware(fw); return rc;}/** * notifies all clients registered with the device, notifies hotplugs, * frees all buffers and coredev object * * @param coredev pointer to a coredev object returned by * smscore_register_device * * @return 0 on success, <0 on error. */void smscore_unregister_device(struct smscore_device_t *coredev){ struct smscore_buffer_t *cb; int num_buffers = 0; int retry = 0; kmutex_lock(&g_smscore_deviceslock); smscore_notify_clients(coredev); smscore_notify_callbacks(coredev, NULL, 0); /* at this point all buffers should be back * onresponse must no longer be called */ while (1) { while ((cb = smscore_getbuffer(coredev))) { kfree(cb); num_buffers++; } if (num_buffers == coredev->num_buffers) break; if (++retry > 10) { sms_info("exiting although " "not all buffers released."); break; } sms_info("waiting for %d buffer(s)", coredev->num_buffers - num_buffers); msleep(100); } sms_info("freed %d buffers", num_buffers); if (coredev->common_buffer) dma_free_coherent(NULL, coredev->common_buffer_size, coredev->common_buffer, coredev->common_buffer_phys); list_del(&coredev->entry); kfree(coredev); kmutex_unlock(&g_smscore_deviceslock); sms_info("device %p destroyed", coredev);}static int smscore_detect_mode(struct smscore_device_t *coredev){ void *buffer = kmalloc(sizeof(struct SmsMsgHdr_ST) + SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); struct SmsMsgHdr_ST *msg = (struct SmsMsgHdr_ST *) SMS_ALIGN_ADDRESS(buffer); int rc; if (!buffer) return -ENOMEM; SMS_INIT_MSG(msg, MSG_SMS_GET_VERSION_EX_REQ, sizeof(struct SmsMsgHdr_ST)); rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength, &coredev->version_ex_done); if (rc == -ETIME) { sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try"); if (wait_for_completion_timeout(&coredev->resume_done, msecs_to_jiffies(5000))) { rc = smscore_sendrequest_and_wait( coredev, msg, msg->msgLength, &coredev->version_ex_done); if (rc < 0) sms_err("MSG_SMS_GET_VERSION_EX_REQ failed " "second try, rc %d", rc); } else rc = -ETIME; } kfree(buffer); return rc;}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", "none", "none"}, /*DABIP*/ {"none", "none", "none", "none"}, /*BDA*/ {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"}, /*ISDBT*/ {"none", "isdbt_nova_12mhz.inp", "dvb_nova_12mhz.inp", "none"}, /*ISDBTBDA*/ {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"}, /*CMMB*/ {"none", "none", "none", "cmmb_vega_12mhz.inp"}};static inline char *sms_get_fw_name(struct smscore_device_t *coredev, int mode, enum sms_device_type_st type){ char **fw = sms_get_board(smscore_get_board_id(coredev))->fw; return (fw && fw[mode]) ? fw[mode] : smscore_fw_lkup[mode][type];}/** * calls device handler to change mode of operation * NOTE: stellar/usb may disconnect when changing mode * * @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_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 < DEVICE_MODE_DVBT || mode > DEVICE_MODE_RAW_TUNER) { sms_err("invalid mode specified %d", mode); return -EINVAL; } smscore_registry_setmode(coredev->devpath, mode); if (!(coredev->device_flags & SMS_DEVICE_NOT_READY)) { rc = smscore_detect_mode(coredev); if (rc < 0) { sms_err("mode detect failed %d", rc); return rc; } } if (coredev->mode == mode) { sms_info("device mode %d already set", mode); return 0; } 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); /* try again with the default firmware */ fw_filename = smscore_fw_lkup[mode][type]; rc = smscore_load_firmware_from_file(coredev, fw_filename, NULL); if (rc < 0) { sms_warn("error %d loading " "firmware: %s", rc, fw_filename); 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); } else { sms_err("Could not allocate buffer for " "init device message."); rc = -ENOMEM; } } else { if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) { sms_err("invalid mode specified %d", mode); return -EINVAL; } smscore_registry_setmode(coredev->devpath, mode); if (coredev->detectmode_handler) coredev->detectmode_handler(coredev->context, &coredev->mode); if (coredev->mode != mode && coredev->setmode_handler) rc = coredev->setmode_handler(coredev->context, mode); } if (rc >= 0) { coredev->mode = mode; coredev->device_flags &= ~SMS_DEVICE_NOT_READY; } if (rc != 0) sms_err("return error code %d.", rc); return rc;}/** * calls device handler to get current mode of operation * * @param coredev pointer to a coredev object returned by * smscore_register_device * * @return current mode */int smscore_get_device_mode(struct smscore_device_t *coredev){ return coredev->mode;}/** * find client by response id & type within the clients list.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -