diff --git a/hal/Hal.cpp b/hal/Hal.cpp index f8483e67ec6..37ea6dd74e0 100644 --- a/hal/Hal.cpp +++ b/hal/Hal.cpp @@ -781,5 +781,208 @@ SetProcessPriority(int aPid, ProcessPriority aPriority) } } +static StaticAutoPtr > sFMRadioObservers; + +static void +InitializeFMRadioObserver() +{ + if (!sFMRadioObservers) { + sFMRadioObservers = new ObserverList; + ClearOnShutdown(&sFMRadioObservers); + } +} + +void +RegisterFMRadioObserver(FMRadioObserver* aFMRadioObserver) { + AssertMainThread(); + InitializeFMRadioObserver(); + sFMRadioObservers->AddObserver(aFMRadioObserver); +} + +void +UnregisterFMRadioObserver(FMRadioObserver* aFMRadioObserver) { + AssertMainThread(); + InitializeFMRadioObserver(); + sFMRadioObservers->RemoveObserver(aFMRadioObserver); +} + +void +NotifyFMRadioStatus(const FMRadioOperationInformation& aFMRadioState) { + InitializeFMRadioObserver(); + sFMRadioObservers->Broadcast(aFMRadioState); +} + +void +EnableFMRadio(const FMRadioSettings& aInfo) { + AssertMainThread(); + PROXY_IF_SANDBOXED(EnableFMRadio(aInfo)); +} + +void +DisableFMRadio() { + AssertMainThread(); + PROXY_IF_SANDBOXED(DisableFMRadio()); +} + +void +FMRadioSeek(const FMRadioSeekDirection& aDirection) { + AssertMainThread(); + PROXY_IF_SANDBOXED(FMRadioSeek(aDirection)); +} + +void +GetFMRadioSettings(FMRadioSettings* aInfo) { + AssertMainThread(); + PROXY_IF_SANDBOXED(GetFMRadioSettings(aInfo)); +} + +void +SetFMRadioFrequency(const uint32_t aFrequency) { + AssertMainThread(); + PROXY_IF_SANDBOXED(SetFMRadioFrequency(aFrequency)); +} + +uint32_t +GetFMRadioFrequency() { + AssertMainThread(); + RETURN_PROXY_IF_SANDBOXED(GetFMRadioFrequency()); +} + +bool +IsFMRadioOn() { + AssertMainThread(); + RETURN_PROXY_IF_SANDBOXED(IsFMRadioOn()); +} + +uint32_t +GetFMRadioSignalStrength() { + AssertMainThread(); + RETURN_PROXY_IF_SANDBOXED(GetFMRadioSignalStrength()); +} + +void +CancelFMRadioSeek() { + AssertMainThread(); + PROXY_IF_SANDBOXED(CancelFMRadioSeek()); +} + +FMRadioSettings +GetFMBandSettings(FMRadioCountry aCountry) { + FMRadioSettings settings; + + switch (aCountry) { + case FM_RADIO_COUNTRY_US: + case FM_RADIO_COUNTRY_EU: + settings.upperLimit() = 108000; + settings.lowerLimit() = 87800; + settings.spaceType() = 200; + settings.preEmphasis() = 75; + break; + case FM_RADIO_COUNTRY_JP_STANDARD: + settings.upperLimit() = 76000; + settings.lowerLimit() = 90000; + settings.spaceType() = 100; + settings.preEmphasis() = 50; + break; + case FM_RADIO_COUNTRY_CY: + case FM_RADIO_COUNTRY_DE: + case FM_RADIO_COUNTRY_DK: + case FM_RADIO_COUNTRY_ES: + case FM_RADIO_COUNTRY_FI: + case FM_RADIO_COUNTRY_FR: + case FM_RADIO_COUNTRY_HU: + case FM_RADIO_COUNTRY_IR: + case FM_RADIO_COUNTRY_IT: + case FM_RADIO_COUNTRY_KW: + case FM_RADIO_COUNTRY_LT: + case FM_RADIO_COUNTRY_ML: + case FM_RADIO_COUNTRY_NO: + case FM_RADIO_COUNTRY_OM: + case FM_RADIO_COUNTRY_PG: + case FM_RADIO_COUNTRY_NL: + case FM_RADIO_COUNTRY_CZ: + case FM_RADIO_COUNTRY_UK: + case FM_RADIO_COUNTRY_RW: + case FM_RADIO_COUNTRY_SN: + case FM_RADIO_COUNTRY_SI: + case FM_RADIO_COUNTRY_ZA: + case FM_RADIO_COUNTRY_SE: + case FM_RADIO_COUNTRY_CH: + case FM_RADIO_COUNTRY_TW: + case FM_RADIO_COUNTRY_UA: + settings.upperLimit() = 108000; + settings.lowerLimit() = 87500; + settings.spaceType() = 100; + settings.preEmphasis() = 50; + break; + case FM_RADIO_COUNTRY_VA: + case FM_RADIO_COUNTRY_MA: + case FM_RADIO_COUNTRY_TR: + settings.upperLimit() = 10800; + settings.lowerLimit() = 87500; + settings.spaceType() = 100; + settings.preEmphasis() = 75; + break; + case FM_RADIO_COUNTRY_AU: + case FM_RADIO_COUNTRY_BD: + settings.upperLimit() = 108000; + settings.lowerLimit() = 87500; + settings.spaceType() = 200; + settings.preEmphasis() = 75; + break; + case FM_RADIO_COUNTRY_AW: + case FM_RADIO_COUNTRY_BS: + case FM_RADIO_COUNTRY_CO: + case FM_RADIO_COUNTRY_KR: + settings.upperLimit() = 108000; + settings.lowerLimit() = 88000; + settings.spaceType() = 200; + settings.preEmphasis() = 75; + break; + case FM_RADIO_COUNTRY_EC: + settings.upperLimit() = 108000; + settings.lowerLimit() = 88000; + settings.spaceType() = 200; + settings.preEmphasis() = 0; + break; + case FM_RADIO_COUNTRY_GM: + settings.upperLimit() = 108000; + settings.lowerLimit() = 88000; + settings.spaceType() = 0; + settings.preEmphasis() = 75; + break; + case FM_RADIO_COUNTRY_QA: + settings.upperLimit() = 108000; + settings.lowerLimit() = 88000; + settings.spaceType() = 200; + settings.preEmphasis() = 50; + break; + case FM_RADIO_COUNTRY_SG: + settings.upperLimit() = 108000; + settings.lowerLimit() = 88000; + settings.spaceType() = 200; + settings.preEmphasis() = 50; + break; + case FM_RADIO_COUNTRY_IN: + settings.upperLimit() = 100000; + settings.lowerLimit() = 108000; + settings.spaceType() = 100; + settings.preEmphasis() = 50; + break; + case FM_RADIO_COUNTRY_NZ: + settings.upperLimit() = 100000; + settings.lowerLimit() = 88000; + settings.spaceType() = 50; + settings.preEmphasis() = 50; + break; + case FM_RADIO_COUNTRY_USER_DEFINED: + break; + default: + MOZ_ASSERT(0); + break; + }; + return settings; +} + } // namespace hal } // namespace mozilla diff --git a/hal/Hal.h b/hal/Hal.h index afe066f12dd..dd050bad16a 100644 --- a/hal/Hal.h +++ b/hal/Hal.h @@ -437,6 +437,73 @@ bool SetAlarm(int32_t aSeconds, int32_t aNanoseconds); */ void SetProcessPriority(int aPid, hal::ProcessPriority aPriority); +/** + * Register an observer for the FM radio. + */ +void RegisterFMRadioObserver(hal::FMRadioObserver* aRadioObserver); + +/** + * Unregister the observer for the FM radio. + */ +void UnregisterFMRadioObserver(hal::FMRadioObserver* aRadioObserver); + +/** + * Notify observers that a call to EnableFMRadio, DisableFMRadio, or FMRadioSeek + * has completed, and indicate what the call returned. + */ +void NotifyFMRadioStatus(const hal::FMRadioOperationInformation& aRadioState); + +/** + * Enable the FM radio and configure it according to the settings in aInfo. + */ +void EnableFMRadio(const hal::FMRadioSettings& aInfo); + +/** + * Disable the FM radio. + */ +void DisableFMRadio(); + +/** + * Seek to an available FM radio station. + * + */ +void FMRadioSeek(const hal::FMRadioSeekDirection& aDirection); + +/** + * Get the current FM radio settings. + */ +void GetFMRadioSettings(hal::FMRadioSettings* aInfo); + +/** + * Set the FM radio's frequency. + */ +void SetFMRadioFrequency(const uint32_t frequency); + +/** + * Get the FM radio's frequency. + */ +uint32_t GetFMRadioFrequency(); + +/** + * Get FM radio power state + */ +bool IsFMRadioOn(); + +/** + * Get FM radio signal strength + */ +uint32_t GetFMRadioSignalStrength(); + +/** + * Cancel FM radio seeking + */ +void CancelFMRadioSeek(); + +/** + * Get FM radio band settings by country. + */ +hal::FMRadioSettings GetFMBandSettings(hal::FMRadioCountry aCountry); + } // namespace MOZ_HAL_NAMESPACE } // namespace mozilla diff --git a/hal/HalTypes.h b/hal/HalTypes.h index e93147e02c6..9dd7f3f6e92 100644 --- a/hal/HalTypes.h +++ b/hal/HalTypes.h @@ -81,6 +81,82 @@ enum SystemTimeChange { SYS_TIME_CHANGE_GUARD }; +class FMRadioOperationInformation; + +enum FMRadioOperation { + FM_RADIO_OPERATION_UNKNOWN = -1, + FM_RADIO_OPERATION_ENABLE, + FM_RADIO_OPERATION_DISABLE, + FM_RADIO_OPERATION_SEEK, + NUM_FM_RADIO_OPERATION +}; + +enum FMRadioOperationStatus { + FM_RADIO_OPERATION_STATUS_UNKNOWN = -1, + FM_RADIO_OPERATION_STATUS_SUCCESS, + FM_RADIO_OPERATION_STATUS_FAIL, + NUM_FM_RADIO_OPERATION_STATUS +}; + +enum FMRadioSeekDirection { + FM_RADIO_SEEK_DIRECTION_UNKNOWN = -1, + FM_RADIO_SEEK_DIRECTION_UP, + FM_RADIO_SEEK_DIRECTION_DOWN, + NUM_FM_RADIO_SEEK_DIRECTION +}; + +enum FMRadioCountry { + FM_RADIO_COUNTRY_UNKNOWN = -1, + FM_RADIO_COUNTRY_US, //USA + FM_RADIO_COUNTRY_EU, + FM_RADIO_COUNTRY_JP_STANDARD, + FM_RADIO_COUNTRY_JP_WIDE, + FM_RADIO_COUNTRY_DE, //Germany + FM_RADIO_COUNTRY_AW, //Aruba + FM_RADIO_COUNTRY_AU, //Australlia + FM_RADIO_COUNTRY_BS, //Bahamas + FM_RADIO_COUNTRY_BD, //Bangladesh + FM_RADIO_COUNTRY_CY, //Cyprus + FM_RADIO_COUNTRY_VA, //Vatican + FM_RADIO_COUNTRY_CO, //Colombia + FM_RADIO_COUNTRY_KR, //Korea + FM_RADIO_COUNTRY_DK, //Denmark + FM_RADIO_COUNTRY_EC, //Ecuador + FM_RADIO_COUNTRY_ES, //Spain + FM_RADIO_COUNTRY_FI, //Finland + FM_RADIO_COUNTRY_FR, //France + FM_RADIO_COUNTRY_GM, //Gambia + FM_RADIO_COUNTRY_HU, //Hungary + FM_RADIO_COUNTRY_IN, //India + FM_RADIO_COUNTRY_IR, //Iran + FM_RADIO_COUNTRY_IT, //Italy + FM_RADIO_COUNTRY_KW, //Kuwait + FM_RADIO_COUNTRY_LT, //Lithuania + FM_RADIO_COUNTRY_ML, //Mali + FM_RADIO_COUNTRY_MA, //Morocco + FM_RADIO_COUNTRY_NO, //Norway + FM_RADIO_COUNTRY_NZ, //New Zealand + FM_RADIO_COUNTRY_OM, //Oman + FM_RADIO_COUNTRY_PG, //Papua New Guinea + FM_RADIO_COUNTRY_NL, //Netherlands + FM_RADIO_COUNTRY_QA, //Qatar + FM_RADIO_COUNTRY_CZ, //Czech Republic + FM_RADIO_COUNTRY_UK, //United Kingdom of Great Britain and Northern Ireland + FM_RADIO_COUNTRY_RW, //Rwandese Republic + FM_RADIO_COUNTRY_SN, //Senegal + FM_RADIO_COUNTRY_SG, //Singapore + FM_RADIO_COUNTRY_SI, //Slovenia + FM_RADIO_COUNTRY_ZA, //South Africa + FM_RADIO_COUNTRY_SE, //Sweden + FM_RADIO_COUNTRY_CH, //Switzerland + FM_RADIO_COUNTRY_TW, //Taiwan + FM_RADIO_COUNTRY_TR, //Turkey + FM_RADIO_COUNTRY_UA, //Ukraine + FM_RADIO_COUNTRY_USER_DEFINED, + NUM_FM_RADIO_COUNTRY +}; + +typedef Observer FMRadioObserver; } // namespace hal } // namespace mozilla @@ -163,6 +239,45 @@ struct ParamTraits mozilla::hal::SYS_TIME_CHANGE_GUARD> {}; +/** + * Serializer for FMRadioOperation + */ +template <> +struct ParamTraits: + public EnumSerializer +{}; + +/** + * Serializer for FMRadioOperationStatus + */ +template <> +struct ParamTraits: + public EnumSerializer +{}; + +/** + * Serializer for FMRadioSeekDirection + */ +template <> +struct ParamTraits: + public EnumSerializer +{}; + +/** + * Serializer for FMRadioCountry + **/ +template <> +struct ParamTraits: + public EnumSerializer +{}; } // namespace IPC #endif // mozilla_hal_Types_h diff --git a/hal/Makefile.in b/hal/Makefile.in index dacbe3e3847..9f3fcd81d37 100644 --- a/hal/Makefile.in +++ b/hal/Makefile.in @@ -57,6 +57,7 @@ CPPSRCS += \ GonkSensor.cpp \ UeventPoller.cpp \ GonkSwitch.cpp \ + GonkFMRadio.cpp \ $(NULL) else ifeq (Linux,$(OS_TARGET)) CPPSRCS += \ @@ -125,6 +126,7 @@ CPPSRCS += \ FallbackSwitch.cpp \ FallbackScreenPower.cpp \ FallbackProcessPriority.cpp \ + FallbackFMRadio.cpp \ $(NULL) endif #} diff --git a/hal/fallback/FallbackFMRadio.cpp b/hal/fallback/FallbackFMRadio.cpp new file mode 100644 index 00000000000..664928b9a77 --- /dev/null +++ b/hal/fallback/FallbackFMRadio.cpp @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 et ft=cpp : */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "Hal.h" + +namespace mozilla { +namespace hal_impl { + +void +EnableFMRadio(const hal::FMRadioSettings& aInfo) +{} + +void +DisableFMRadio() +{} + +void +FMRadioSeek(const hal::FMRadioSeekDirection& aDirection) +{} + +void +GetFMRadioSettings(hal::FMRadioSettings* aInfo) +{ + aInfo->country() = hal::FM_RADIO_COUNTRY_UNKNOWN; + aInfo->upperLimit() = 0; + aInfo->lowerLimit() = 0; + aInfo->spaceType() = 0; + aInfo->preEmphasis() = 0; +} + +void +SetFMRadioFrequency(const uint32_t frequency) +{} + +uint32_t +GetFMRadioFrequency() +{ + return 0; +} + +bool +IsFMRadioOn() +{ + return false; +} + +uint32_t +GetFMRadioSignalStrength() +{ + return 0; +} + +void +CancelFMRadioSeek() +{} + +} // hal_impl +} // namespace mozilla diff --git a/hal/gonk/GonkFMRadio.cpp b/hal/gonk/GonkFMRadio.cpp new file mode 100644 index 00000000000..aca7c69e16c --- /dev/null +++ b/hal/gonk/GonkFMRadio.cpp @@ -0,0 +1,324 @@ +/* Copyright 2012 Mozilla Foundation and Mozilla contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Hal.h" +#include "tavarua.h" +#include "nsThreadUtils.h" +#include "mozilla/FileUtils.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace mozilla { +namespace hal_impl { + +uint32_t GetFMRadioFrequency(); + +static int sRadioFD; +static bool sRadioEnabled; +static pthread_t sMonitorThread; + +static int +setControl(uint32_t id, int32_t value) +{ + struct v4l2_control control; + control.id = id; + control.value = value; + return ioctl(sRadioFD, VIDIOC_S_CTRL, &control); +} + +class RadioUpdate : public nsRunnable { + hal::FMRadioOperation mOp; +public: + RadioUpdate(hal::FMRadioOperation op) + : mOp(op) + {} + + NS_IMETHOD Run() { + hal::FMRadioOperationInformation info; + info.operation() = mOp; + info.status() = hal::FM_RADIO_OPERATION_STATUS_SUCCESS; + info.frequency() = GetFMRadioFrequency(); + hal::NotifyFMRadioStatus(info); + return NS_OK; + } +}; + +static void * +pollTavaruaRadio(void *) +{ + uint8_t buf[128]; + struct v4l2_buffer buffer = {0}; + buffer.index = 1; + buffer.type = V4L2_BUF_TYPE_PRIVATE; + buffer.length = sizeof(buf); + buffer.m.userptr = (long unsigned int)buf; + + while (sRadioEnabled) { + int rc = ioctl(sRadioFD, VIDIOC_DQBUF, &buffer); + if (rc) + return NULL; + + for (unsigned int i = 0; i < buffer.bytesused; i++) { + switch (buf[i]) { + case TAVARUA_EVT_RADIO_READY: + NS_DispatchToMainThread(new RadioUpdate(hal::FM_RADIO_OPERATION_ENABLE)); + break; + case TAVARUA_EVT_SEEK_COMPLETE: + NS_DispatchToMainThread(new RadioUpdate(hal::FM_RADIO_OPERATION_SEEK)); + break; + default: + break; + } + } + } + + return NULL; +} + +void +EnableFMRadio(const hal::FMRadioSettings& aInfo) +{ + if (sRadioEnabled) { + HAL_LOG(("Radio already enabled!")); + return; + } + + mozilla::ScopedClose fd(open("/dev/radio0", O_RDWR)); + if (fd < 0) { + HAL_LOG(("Unable to open radio device")); + return; + } + + struct v4l2_capability cap; + int rc = ioctl(fd, VIDIOC_QUERYCAP, &cap); + if (rc < 0) { + HAL_LOG(("Unable to query radio device")); + return; + } + + HAL_LOG(("Radio: %s (%s)\n", cap.driver, cap.card)); + + if (!(cap.capabilities & V4L2_CAP_RADIO)) { + HAL_LOG(("/dev/radio0 isn't a radio")); + return; + } + + if (!(cap.capabilities & V4L2_CAP_TUNER)) { + HAL_LOG(("/dev/radio0 doesn't support the tuner interface")); + return; + } + sRadioFD = fd; + + // Tavarua specific start + char command[64]; + snprintf(command, sizeof(command), "/system/bin/fm_qsoc_patches %d 0", cap.version); + rc = system(command); + if (rc) { + HAL_LOG(("Unable to initialize radio")); + return; + } + + rc = setControl(V4L2_CID_PRIVATE_TAVARUA_STATE, FM_RECV); + if (rc < 0) { + HAL_LOG(("Unable to turn on radio |%s|", strerror(errno))); + return; + } + + int preEmphasis = aInfo.preEmphasis() <= 50; + rc = setControl(V4L2_CID_PRIVATE_TAVARUA_EMPHASIS, preEmphasis); + if (rc) { + HAL_LOG(("Unable to configure preemphasis")); + return; + } + + rc = setControl(V4L2_CID_PRIVATE_TAVARUA_RDS_STD, 0); + if (rc) { + HAL_LOG(("Unable to configure RDS")); + return; + } + + int spacing; + switch (aInfo.spaceType()) { + case 50: + spacing = FM_CH_SPACE_50KHZ; + break; + case 100: + spacing = FM_CH_SPACE_100KHZ; + break; + case 200: + spacing = FM_CH_SPACE_200KHZ; + break; + default: + HAL_LOG(("Unsupported space value - %d", aInfo.spaceType())); + return; + } + + rc = setControl(V4L2_CID_PRIVATE_TAVARUA_SPACING, spacing); + if (rc) { + HAL_LOG(("Unable to configure spacing")); + return; + } + + /* + * Frequency conversions + * + * HAL uses units of 1k for frequencies + * V4L2 uses units of 62.5kHz + * Multiplying by (10000 / 625) converts from HAL units to V4L2. + */ + + struct v4l2_tuner tuner = {0}; + tuner.rangelow = (aInfo.lowerLimit() * 10000) / 625; + tuner.rangehigh = (aInfo.upperLimit() * 10000) / 625; + rc = ioctl(fd, VIDIOC_S_TUNER, &tuner); + if (rc < 0) { + HAL_LOG(("Unable to adjust band limits")); + return; + } + + rc = setControl(V4L2_CID_PRIVATE_TAVARUA_REGION, TAVARUA_REGION_OTHER); + if (rc < 0) { + HAL_LOG(("Unable to configure region")); + return; + } + + rc = setControl(V4L2_CID_PRIVATE_TAVARUA_SET_AUDIO_PATH, FM_DIGITAL_PATH); + if (rc < 0) { + HAL_LOG(("Unable to set audio path")); + return; + } + + pthread_create(&sMonitorThread, NULL, pollTavaruaRadio, NULL); + // Tavarua specific end + + fd.forget(); + sRadioEnabled = true; +} + +void +DisableFMRadio() +{ + if (!sRadioEnabled) + return; + + sRadioEnabled = false; + + // Tavarua specific start + int rc = setControl(V4L2_CID_PRIVATE_TAVARUA_STATE, FM_OFF); + if (rc < 0) { + HAL_LOG(("Unable to turn off radio")); + } + // Tavarua specific end + + pthread_join(sMonitorThread, NULL); + + close(sRadioFD); + + hal::FMRadioOperationInformation info; + info.operation() = hal::FM_RADIO_OPERATION_DISABLE; + info.status() = hal::FM_RADIO_OPERATION_STATUS_SUCCESS; + hal::NotifyFMRadioStatus(info); +} + +void +FMRadioSeek(const hal::FMRadioSeekDirection& aDirection) +{ + struct v4l2_hw_freq_seek seek = {0}; + seek.type = V4L2_TUNER_RADIO; + seek.seek_upward = aDirection == hal::FMRadioSeekDirection::FM_RADIO_SEEK_DIRECTION_UP; + int rc = ioctl(sRadioFD, VIDIOC_S_HW_FREQ_SEEK, &seek); + if (rc < 0) { + HAL_LOG(("Could not initiate hardware seek")); + return; + } +} + +void +GetFMRadioSettings(hal::FMRadioSettings* aInfo) +{ + if (!sRadioEnabled) { + return; + } + + struct v4l2_tuner tuner = {0}; + int rc = ioctl(sRadioFD, VIDIOC_G_TUNER, &tuner); + if (rc < 0) { + HAL_LOG(("Could not query fm radio for settings")); + return; + } + + aInfo->upperLimit() = (tuner.rangehigh * 625) / 10000; + aInfo->lowerLimit() = (tuner.rangelow * 625) / 10000; +} + +void +SetFMRadioFrequency(const uint32_t frequency) +{ + struct v4l2_frequency freq = {0}; + freq.type = V4L2_TUNER_RADIO; + freq.frequency = (frequency * 10000) / 625; + + int rc = ioctl(sRadioFD, VIDIOC_S_FREQUENCY, &freq); + if (rc < 0) + HAL_LOG(("Could not set radio frequency")); +} + +uint32_t +GetFMRadioFrequency() +{ + if (!sRadioEnabled) + return 0; + + struct v4l2_frequency freq; + int rc = ioctl(sRadioFD, VIDIOC_G_FREQUENCY, &freq); + if (rc < 0) { + HAL_LOG(("Could not get radio frequency")); + return 0; + } + + return (freq.frequency * 625) / 10000; +} + +bool +IsFMRadioOn() +{ + return sRadioEnabled; +} + +uint32_t +GetFMRadioSignalStrength() +{ + struct v4l2_tuner tuner = {0}; + int rc = ioctl(sRadioFD, VIDIOC_G_TUNER, &tuner); + if (rc < 0) { + HAL_LOG(("Could not query fm radio for signal strength")); + return 0; + } + + return tuner.signal; +} + +void +CancelFMRadioSeek() +{} + +} // hal_impl +} // namespace mozilla diff --git a/hal/gonk/tavarua.h b/hal/gonk/tavarua.h new file mode 100644 index 00000000000..4eb3483a846 --- /dev/null +++ b/hal/gonk/tavarua.h @@ -0,0 +1,484 @@ +#ifndef __LINUX_TAVARUA_H +#define __LINUX_TAVARUA_H + +/* This is a Linux header generated by "make headers_install" */ + +#include +#include +#include + + +#undef FM_DEBUG + +/* constants */ +#define RDS_BLOCKS_NUM (4) +#define BYTES_PER_BLOCK (3) +#define MAX_PS_LENGTH (96) +#define MAX_RT_LENGTH (64) + +#define XFRDAT0 (0x20) +#define XFRDAT1 (0x21) +#define XFRDAT2 (0x22) + +#define INTDET_PEEK_MSB (0x88) +#define INTDET_PEEK_LSB (0x26) + +#define RMSSI_PEEK_MSB (0x88) +#define RMSSI_PEEK_LSB (0xA8) + +#define MPX_DCC_BYPASS_POKE_MSB (0x88) +#define MPX_DCC_BYPASS_POKE_LSB (0xC0) + +#define MPX_DCC_PEEK_MSB_REG1 (0x88) +#define MPX_DCC_PEEK_LSB_REG1 (0xC2) + +#define MPX_DCC_PEEK_MSB_REG2 (0x88) +#define MPX_DCC_PEEK_LSB_REG2 (0xC3) + +#define MPX_DCC_PEEK_MSB_REG3 (0x88) +#define MPX_DCC_PEEK_LSB_REG3 (0xC4) + +#define ON_CHANNEL_TH_MSB (0x0B) +#define ON_CHANNEL_TH_LSB (0xA8) + +#define OFF_CHANNEL_TH_MSB (0x0B) +#define OFF_CHANNEL_TH_LSB (0xAC) + +#define ENF_200Khz (1) +#define SRCH200KHZ_OFFSET (7) +#define SRCH_MASK (1 << SRCH200KHZ_OFFSET) + +/* Standard buffer size */ +#define STD_BUF_SIZE (128) +/* Search direction */ +#define SRCH_DIR_UP (0) +#define SRCH_DIR_DOWN (1) + +/* control options */ +#define CTRL_ON (1) +#define CTRL_OFF (0) + +#define US_LOW_BAND (87.5) +#define US_HIGH_BAND (108) + +/* constant for Tx */ + +#define MASK_PI (0x0000FFFF) +#define MASK_PI_MSB (0x0000FF00) +#define MASK_PI_LSB (0x000000FF) +#define MASK_PTY (0x0000001F) +#define MASK_TXREPCOUNT (0x0000000F) + +#undef FMDBG +#ifdef FM_DEBUG + #define FMDBG(fmt, args...) printk(KERN_INFO "tavarua_radio: " fmt, ##args) +#else + #define FMDBG(fmt, args...) +#endif + +#undef FMDERR +#define FMDERR(fmt, args...) printk(KERN_INFO "tavarua_radio: " fmt, ##args) + +#undef FMDBG_I2C +#ifdef FM_DEBUG_I2C + #define FMDBG_I2C(fmt, args...) printk(KERN_INFO "fm_i2c: " fmt, ##args) +#else + #define FMDBG_I2C(fmt, args...) +#endif + +/* function declarations */ +/* FM Core audio paths. */ +#define TAVARUA_AUDIO_OUT_ANALOG_OFF (0) +#define TAVARUA_AUDIO_OUT_ANALOG_ON (1) +#define TAVARUA_AUDIO_OUT_DIGITAL_OFF (0) +#define TAVARUA_AUDIO_OUT_DIGITAL_ON (1) + +int tavarua_set_audio_path(int digital_on, int analog_on); + +/* defines and enums*/ + +#define MARIMBA_A0 0x01010013 +#define MARIMBA_2_1 0x02010204 +#define BAHAMA_1_0 0x0302010A +#define BAHAMA_2_0 0x04020205 +#define WAIT_TIMEOUT 2000 +#define RADIO_INIT_TIME 15 +#define TAVARUA_DELAY 10 +/* + * The frequency is set in units of 62.5 Hz when using V4L2_TUNER_CAP_LOW, + * 62.5 kHz otherwise. + * The tuner is able to have a channel spacing of 50, 100 or 200 kHz. + * tuner->capability is therefore set to V4L2_TUNER_CAP_LOW + * The FREQ_MUL is then: 1 MHz / 62.5 Hz = 16000 + */ +#define FREQ_MUL (1000000 / 62.5) + +enum v4l2_cid_private_tavarua_t { + V4L2_CID_PRIVATE_TAVARUA_SRCHMODE = (V4L2_CID_PRIVATE_BASE + 1), + V4L2_CID_PRIVATE_TAVARUA_SCANDWELL, + V4L2_CID_PRIVATE_TAVARUA_SRCHON, + V4L2_CID_PRIVATE_TAVARUA_STATE, + V4L2_CID_PRIVATE_TAVARUA_TRANSMIT_MODE, + V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK, + V4L2_CID_PRIVATE_TAVARUA_REGION, + V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH, + V4L2_CID_PRIVATE_TAVARUA_SRCH_PTY, + V4L2_CID_PRIVATE_TAVARUA_SRCH_PI, + V4L2_CID_PRIVATE_TAVARUA_SRCH_CNT, + V4L2_CID_PRIVATE_TAVARUA_EMPHASIS, + V4L2_CID_PRIVATE_TAVARUA_RDS_STD, + V4L2_CID_PRIVATE_TAVARUA_SPACING, + V4L2_CID_PRIVATE_TAVARUA_RDSON, + V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC, + V4L2_CID_PRIVATE_TAVARUA_LP_MODE, + V4L2_CID_PRIVATE_TAVARUA_ANTENNA, + V4L2_CID_PRIVATE_TAVARUA_RDSD_BUF, + V4L2_CID_PRIVATE_TAVARUA_PSALL, + /*v4l2 Tx controls*/ + V4L2_CID_PRIVATE_TAVARUA_TX_SETPSREPEATCOUNT, + V4L2_CID_PRIVATE_TAVARUA_STOP_RDS_TX_PS_NAME, + V4L2_CID_PRIVATE_TAVARUA_STOP_RDS_TX_RT, + V4L2_CID_PRIVATE_TAVARUA_IOVERC, + V4L2_CID_PRIVATE_TAVARUA_INTDET, + V4L2_CID_PRIVATE_TAVARUA_MPX_DCC, + V4L2_CID_PRIVATE_TAVARUA_AF_JUMP, + V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA, + V4L2_CID_PRIVATE_TAVARUA_HLSI, + + /* + * Here we have IOCTl's that are specific to IRIS + * (V4L2_CID_PRIVATE_BASE + 0x1E to V4L2_CID_PRIVATE_BASE + 0x28) + */ + V4L2_CID_PRIVATE_SOFT_MUTE,/* 0x800001E*/ + V4L2_CID_PRIVATE_RIVA_ACCS_ADDR, + V4L2_CID_PRIVATE_RIVA_ACCS_LEN, + V4L2_CID_PRIVATE_RIVA_PEEK, + V4L2_CID_PRIVATE_RIVA_POKE, + V4L2_CID_PRIVATE_SSBI_ACCS_ADDR, + V4L2_CID_PRIVATE_SSBI_PEEK, + V4L2_CID_PRIVATE_SSBI_POKE, + V4L2_CID_PRIVATE_TX_TONE, + V4L2_CID_PRIVATE_RDS_GRP_COUNTERS, + V4L2_CID_PRIVATE_SET_NOTCH_FILTER,/* 0x8000028 */ + + V4L2_CID_PRIVATE_TAVARUA_SET_AUDIO_PATH,/* 0x8000029 */ + V4L2_CID_PRIVATE_TAVARUA_DO_CALIBRATION,/* 0x800002A : IRIS */ + V4L2_CID_PRIVATE_TAVARUA_SRCH_ALGORITHM,/* 0x800002B */ + V4L2_CID_PRIVATE_IRIS_GET_SINR, /* 0x800002C : IRIS */ + V4L2_CID_PRIVATE_INTF_LOW_THRESHOLD, /* 0x800002D */ + V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD, /* 0x800002E */ + V4L2_CID_PRIVATE_SINR_THRESHOLD, /* 0x800002F : IRIS */ + V4L2_CID_PRIVATE_SINR_SAMPLES, /* 0x8000030 : IRIS */ + +}; + +enum tavarua_buf_t { + TAVARUA_BUF_SRCH_LIST, + TAVARUA_BUF_EVENTS, + TAVARUA_BUF_RT_RDS, + TAVARUA_BUF_PS_RDS, + TAVARUA_BUF_RAW_RDS, + TAVARUA_BUF_AF_LIST, + TAVARUA_BUF_MAX +}; + +enum tavarua_xfr_t { + TAVARUA_XFR_SYNC, + TAVARUA_XFR_ERROR, + TAVARUA_XFR_SRCH_LIST, + TAVARUA_XFR_RT_RDS, + TAVARUA_XFR_PS_RDS, + TAVARUA_XFR_AF_LIST, + TAVARUA_XFR_MAX +}; + +enum channel_spacing { + FM_CH_SPACE_200KHZ, + FM_CH_SPACE_100KHZ, + FM_CH_SPACE_50KHZ +}; + +enum step_size { + NO_SRCH200khz, + ENF_SRCH200khz +}; + +enum emphasis { + EMP_75, + EMP_50 +}; + +enum rds_std { + RBDS_STD, + RDS_STD +}; + +/* offsets */ +#define RAW_RDS 0x0F +#define RDS_BLOCK 3 + +/* registers*/ +#define MARIMBA_XO_BUFF_CNTRL 0x07 +#define RADIO_REGISTERS 0x30 +#define XFR_REG_NUM 16 +#define STATUS_REG_NUM 3 + +/* TX constants */ +#define HEADER_SIZE 4 +#define TX_ON 0x80 +#define TAVARUA_TX_RT RDS_RT_0 +#define TAVARUA_TX_PS RDS_PS_0 + +enum register_t { + STATUS_REG1 = 0, + STATUS_REG2, + STATUS_REG3, + RDCTRL, + FREQ, + TUNECTRL, + SRCHRDS1, + SRCHRDS2, + SRCHCTRL, + IOCTRL, + RDSCTRL, + ADVCTRL, + AUDIOCTRL, + RMSSI, + IOVERC, + AUDIOIND = 0x1E, + XFRCTRL, + FM_CTL0 = 0xFF, + LEAKAGE_CNTRL = 0xFE, +}; +#define BAHAMA_RBIAS_CTL1 0x07 +#define BAHAMA_FM_MODE_REG 0xFD +#define BAHAMA_FM_CTL1_REG 0xFE +#define BAHAMA_FM_CTL0_REG 0xFF +#define BAHAMA_FM_MODE_NORMAL 0x00 +#define BAHAMA_LDO_DREG_CTL0 0xF0 +#define BAHAMA_LDO_AREG_CTL0 0xF4 + +/* Radio Control */ +#define RDCTRL_STATE_OFFSET 0 +#define RDCTRL_STATE_MASK (3 << RDCTRL_STATE_OFFSET) +#define RDCTRL_BAND_OFFSET 2 +#define RDCTRL_BAND_MASK (1 << RDCTRL_BAND_OFFSET) +#define RDCTRL_CHSPACE_OFFSET 3 +#define RDCTRL_CHSPACE_MASK (3 << RDCTRL_CHSPACE_OFFSET) +#define RDCTRL_DEEMPHASIS_OFFSET 5 +#define RDCTRL_DEEMPHASIS_MASK (1 << RDCTRL_DEEMPHASIS_OFFSET) +#define RDCTRL_HLSI_OFFSET 6 +#define RDCTRL_HLSI_MASK (3 << RDCTRL_HLSI_OFFSET) +#define RDSAF_OFFSET 6 +#define RDSAF_MASK (1 << RDSAF_OFFSET) + +/* Tune Control */ +#define TUNE_STATION 0x01 +#define ADD_OFFSET (1 << 1) +#define SIGSTATE (1 << 5) +#define MOSTSTATE (1 << 6) +#define RDSSYNC (1 << 7) +/* Search Control */ +#define SRCH_MODE_OFFSET 0 +#define SRCH_MODE_MASK (7 << SRCH_MODE_OFFSET) +#define SRCH_DIR_OFFSET 3 +#define SRCH_DIR_MASK (1 << SRCH_DIR_OFFSET) +#define SRCH_DWELL_OFFSET 4 +#define SRCH_DWELL_MASK (7 << SRCH_DWELL_OFFSET) +#define SRCH_STATE_OFFSET 7 +#define SRCH_STATE_MASK (1 << SRCH_STATE_OFFSET) + +/* I/O Control */ +#define IOC_HRD_MUTE 0x03 +#define IOC_SFT_MUTE (1 << 2) +#define IOC_MON_STR (1 << 3) +#define IOC_SIG_BLND (1 << 4) +#define IOC_INTF_BLND (1 << 5) +#define IOC_ANTENNA (1 << 6) +#define IOC_ANTENNA_OFFSET 6 +#define IOC_ANTENNA_MASK (1 << IOC_ANTENNA_OFFSET) + +/* RDS Control */ +#define RDS_ON 0x01 +#define RDSCTRL_STANDARD_OFFSET 1 +#define RDSCTRL_STANDARD_MASK (1 << RDSCTRL_STANDARD_OFFSET) + +/* Advanced features controls */ +#define RDSRTEN (1 << 3) +#define RDSPSEN (1 << 4) + +/* Audio path control */ +#define AUDIORX_ANALOG_OFFSET 0 +#define AUDIORX_ANALOG_MASK (1 << AUDIORX_ANALOG_OFFSET) +#define AUDIORX_DIGITAL_OFFSET 1 +#define AUDIORX_DIGITAL_MASK (1 << AUDIORX_DIGITAL_OFFSET) +#define AUDIOTX_OFFSET 2 +#define AUDIOTX_MASK (1 << AUDIOTX_OFFSET) +#define I2SCTRL_OFFSET 3 +#define I2SCTRL_MASK (1 << I2SCTRL_OFFSET) + +/* Search options */ +enum search_t { + SEEK, + SCAN, + SCAN_FOR_STRONG, + SCAN_FOR_WEAK, + RDS_SEEK_PTY, + RDS_SCAN_PTY, + RDS_SEEK_PI, + RDS_AF_JUMP, +}; + +enum audio_path { + FM_DIGITAL_PATH, + FM_ANALOG_PATH +}; +#define SRCH_MODE 0x07 +#define SRCH_DIR 0x08 /* 0-up 1-down */ +#define SCAN_DWELL 0x70 +#define SRCH_ON 0x80 + +/* RDS CONFIG */ +#define RDS_CONFIG_PSALL 0x01 + +#define FM_ENABLE 0x22 +#define SET_REG_FIELD(reg, val, offset, mask) \ + (reg = (reg & ~mask) | (((val) << offset) & mask)) +#define GET_REG_FIELD(reg, offset, mask) ((reg & mask) >> offset) +#define RSH_DATA(val, offset) ((val) >> (offset)) +#define LSH_DATA(val, offset) ((val) << (offset)) +#define GET_ABS_VAL(val) ((val) & (0xFF)) + +enum radio_state_t { + FM_OFF, + FM_RECV, + FM_TRANS, + FM_RESET, +}; + +#define XFRCTRL_WRITE (1 << 7) + +/* Interrupt status */ + +/* interrupt register 1 */ +#define READY (1 << 0) /* Radio ready after powerup or reset */ +#define TUNE (1 << 1) /* Tune completed */ +#define SEARCH (1 << 2) /* Search completed (read FREQ) */ +#define SCANNEXT (1 << 3) /* Scanning for next station */ +#define SIGNAL (1 << 4) /* Signal indicator change (read SIGSTATE) */ +#define INTF (1 << 5) /* Interference cnt has fallen outside range */ +#define SYNC (1 << 6) /* RDS sync state change (read RDSSYNC) */ +#define AUDIO (1 << 7) /* Audio Control indicator (read AUDIOIND) */ + +/* interrupt register 2 */ +#define RDSDAT (1 << 0) /* New unread RDS data group available */ +#define BLOCKB (1 << 1) /* Block-B match condition exists */ +#define PROGID (1 << 2) /* Block-A or Block-C matched stored PI value*/ +#define RDSPS (1 << 3) /* New RDS Program Service Table available */ +#define RDSRT (1 << 4) /* New RDS Radio Text available */ +#define RDSAF (1 << 5) /* New RDS AF List available */ +#define TXRDSDAT (1 << 6) /* Transmitted an RDS group */ +#define TXRDSDONE (1 << 7) /* RDS raw group one-shot transmit completed */ + +/* interrupt register 3 */ +#define TRANSFER (1 << 0) /* Data transfer (XFR) completed */ +#define RDSPROC (1 << 1) /* Dynamic RDS Processing complete */ +#define ERROR (1 << 7) /* Err occurred.Read code to determine cause */ + + +#define FM_TX_PWR_LVL_0 0 /* Lowest power lvl that can be set for Tx */ +#define FM_TX_PWR_LVL_MAX 7 /* Max power lvl for Tx */ +/* Transfer */ +enum tavarua_xfr_ctrl_t { + RDS_PS_0 = 0x01, + RDS_PS_1, + RDS_PS_2, + RDS_PS_3, + RDS_PS_4, + RDS_PS_5, + RDS_PS_6, + RDS_RT_0, + RDS_RT_1, + RDS_RT_2, + RDS_RT_3, + RDS_RT_4, + RDS_AF_0, + RDS_AF_1, + RDS_CONFIG, + RDS_TX_GROUPS, + RDS_COUNT_0, + RDS_COUNT_1, + RDS_COUNT_2, + RADIO_CONFIG, + RX_CONFIG, + RX_TIMERS, + RX_STATIONS_0, + RX_STATIONS_1, + INT_CTRL, + ERROR_CODE, + CHIPID, + CAL_DAT_0 = 0x20, + CAL_DAT_1, + CAL_DAT_2, + CAL_DAT_3, + CAL_CFG_0, + CAL_CFG_1, + DIG_INTF_0, + DIG_INTF_1, + DIG_AGC_0, + DIG_AGC_1, + DIG_AGC_2, + DIG_AUDIO_0, + DIG_AUDIO_1, + DIG_AUDIO_2, + DIG_AUDIO_3, + DIG_AUDIO_4, + DIG_RXRDS, + DIG_DCC, + DIG_SPUR, + DIG_MPXDCC, + DIG_PILOT, + DIG_DEMOD, + DIG_MOST, + DIG_TX_0, + DIG_TX_1, + PHY_TXGAIN = 0x3B, + PHY_CONFIG, + PHY_TXBLOCK, + PHY_TCB, + XFR_PEEK_MODE = 0x40, + XFR_POKE_MODE = 0xC0, + TAVARUA_XFR_CTRL_MAX +}; + +enum tavarua_evt_t { + TAVARUA_EVT_RADIO_READY, + TAVARUA_EVT_TUNE_SUCC, + TAVARUA_EVT_SEEK_COMPLETE, + TAVARUA_EVT_SCAN_NEXT, + TAVARUA_EVT_NEW_RAW_RDS, + TAVARUA_EVT_NEW_RT_RDS, + TAVARUA_EVT_NEW_PS_RDS, + TAVARUA_EVT_ERROR, + TAVARUA_EVT_BELOW_TH, + TAVARUA_EVT_ABOVE_TH, + TAVARUA_EVT_STEREO, + TAVARUA_EVT_MONO, + TAVARUA_EVT_RDS_AVAIL, + TAVARUA_EVT_RDS_NOT_AVAIL, + TAVARUA_EVT_NEW_SRCH_LIST, + TAVARUA_EVT_NEW_AF_LIST, + TAVARUA_EVT_TXRDSDAT, + TAVARUA_EVT_TXRDSDONE, + TAVARUA_EVT_RADIO_DISABLED +}; + +enum tavarua_region_t { + TAVARUA_REGION_US, + TAVARUA_REGION_EU, + TAVARUA_REGION_JAPAN, + TAVARUA_REGION_JAPAN_WIDE, + TAVARUA_REGION_OTHER +}; + +#endif /* __LINUX_TAVARUA_H */ diff --git a/hal/sandbox/PHal.ipdl b/hal/sandbox/PHal.ipdl index 06d410fd6e9..ece1316857a 100644 --- a/hal/sandbox/PHal.ipdl +++ b/hal/sandbox/PHal.ipdl @@ -25,6 +25,10 @@ using mozilla::hal::ProcessPriority; using nsIntRect; using PRTime; using mozilla::hal::SystemTimeChange; +using mozilla::hal::FMRadioCountry; +using mozilla::hal::FMRadioOperation; +using mozilla::hal::FMRadioOperationStatus; +using mozilla::hal::FMRadioSeekDirection; namespace mozilla { @@ -74,6 +78,20 @@ struct ScreenConfiguration { uint32_t pixelDepth; }; +struct FMRadioOperationInformation { + FMRadioOperation operation; + FMRadioOperationStatus status; + uint32_t frequency; +}; + +struct FMRadioSettings { + FMRadioCountry country; + uint32_t upperLimit; + uint32_t lowerLimit; + uint32_t spaceType; + uint32_t preEmphasis; +}; + } // namespace hal namespace hal_sandbox { @@ -88,6 +106,7 @@ child: NotifyScreenConfigurationChange(ScreenConfiguration aScreenOrientation); NotifySwitchChange(SwitchEvent aEvent); NotifySystemTimeChange(SystemTimeChange aReason); + NotifyFMRadioStatus(FMRadioOperationInformation aInfo); parent: Vibrate(uint32_t[] pattern, uint64_t[] id, PBrowser browser); @@ -146,10 +165,24 @@ parent: SetProcessPriority(int aPid, ProcessPriority aPriority); + EnableFMRadio(FMRadioSettings aSettings); + DisableFMRadio(); + FMRadioSeek(FMRadioSeekDirection aDirection); + sync GetFMRadioSettings() + returns (FMRadioSettings settings); + SetFMRadioFrequency(uint32_t frequency); + sync GetFMRadioFrequency() + returns (uint32_t frequency); + sync IsFMRadioOn() + returns (bool radioOn); + sync GetFMRadioSignalStrength() + returns (uint32_t strength); + CancelFMRadioSeek(); + child: NotifySensorChange(SensorData aSensorData); -parent: +parent: EnableSensorNotifications(SensorType aSensor); DisableSensorNotifications(SensorType aSensor); diff --git a/hal/sandbox/SandboxHal.cpp b/hal/sandbox/SandboxHal.cpp index 834664786bc..1d9040c6a85 100644 --- a/hal/sandbox/SandboxHal.cpp +++ b/hal/sandbox/SandboxHal.cpp @@ -295,6 +295,66 @@ SetProcessPriority(int aPid, ProcessPriority aPriority) Hal()->SendSetProcessPriority(aPid, aPriority); } +void +EnableFMRadio(const hal::FMRadioSettings& aSettings) +{ + Hal()->SendEnableFMRadio(aSettings); +} + +void +DisableFMRadio() +{ + Hal()->SendDisableFMRadio(); +} + +void +FMRadioSeek(const hal::FMRadioSeekDirection& aDirection) +{ + Hal()->SendFMRadioSeek(aDirection); +} + +void +GetFMRadioSettings(FMRadioSettings* aSettings) +{ + Hal()->SendGetFMRadioSettings(aSettings); +} + +void +SetFMRadioFrequency(const uint32_t aFrequency) +{ + Hal()->SendSetFMRadioFrequency(aFrequency); +} + +uint32_t +GetFMRadioFrequency() +{ + uint32_t frequency; + Hal()->SendGetFMRadioFrequency(&frequency); + return frequency; +} + +bool +IsFMRadioOn() +{ + bool FMRadioOn; + Hal()->SendIsFMRadioOn(&FMRadioOn); + return FMRadioOn; +} + +uint32_t +GetFMRadioSignalStrength() +{ + uint32_t strength; + Hal()->SendGetFMRadioSignalStrength(&strength); + return strength; +} + +void +CancelFMRadioSeek() +{ + Hal()->SendCancelFMRadioSeek(); +} + class HalParent : public PHalParent , public BatteryObserver , public NetworkObserver @@ -665,6 +725,74 @@ public: { unused << SendNotifySystemTimeChange(aReason); } + + virtual bool + RecvEnableFMRadio(const hal::FMRadioSettings& aSettings) + { + hal::EnableFMRadio(aSettings); + return true; + } + + virtual bool + RecvDisableFMRadio() + { + hal::DisableFMRadio(); + return true; + } + + virtual bool + RecvFMRadioSeek(const hal::FMRadioSeekDirection& aDirection) + { + hal::FMRadioSeek(aDirection); + return true; + } + + virtual bool + RecvGetFMRadioSettings(hal::FMRadioSettings* aSettings) + { + hal::GetFMRadioSettings(aSettings); + return true; + } + + virtual bool + RecvSetFMRadioFrequency(const uint32_t& aFrequency) + { + hal::SetFMRadioFrequency(aFrequency); + return true; + } + + virtual bool + RecvGetFMRadioFrequency(uint32_t* aFrequency) + { + *aFrequency = hal::GetFMRadioFrequency(); + return true; + } + + void Notify(const hal::FMRadioOperationInformation& aRadioStatus) + { + unused << SendNotifyFMRadioStatus(aRadioStatus); + } + + virtual bool + RecvIsFMRadioOn(bool* radioOn) + { + *radioOn = hal::IsFMRadioOn(); + return true; + } + + virtual bool + RecvGetFMRadioSignalStrength(uint32_t* strength) + { + *strength = hal::GetFMRadioSignalStrength(); + return true; + } + + virtual bool + RecvCancelFMRadioSeek() + { + hal::CancelFMRadioSeek(); + return true; + } }; class HalChild : public PHalChild { @@ -707,6 +835,12 @@ public: hal::NotifySystemTimeChange(aReason); return true; } + + virtual bool + RecvNotifyFMRadioStatus(const FMRadioOperationInformation& aRadioStatus) { + hal::NotifyFMRadioStatus(aRadioStatus); + return true; + } }; bool