[Spirit FM] CresCoJeff:
qualcomm API compliance with video4linux

Hi all,

I have a rooted Xperia E C1504 with the Qualcomm tavarua FM chipset, and I'm interested in writing my own small FM radio controller app for it. I can open the radio device driver /dev/radio0 in read-write mode and query the FM tuner capabilities, but every time I try to tune the app fails with errno 5 (I/O error). Below follows my tune() function adapted from some open source TI code here:

#define V4L2_RESERVED_SEGMENT_SIZE_FREQUENCY 8
#define V4L2_RESERVED_SEGMENT_SIZE_TUNER 4
...
struct RadioDescriptor
{
typedef char boolean;

/* V4l2 structures */
struct v4l2_capability vCapabilities;
struct v4l2_tuner vTuner;
struct v4l2_control vctrl;
struct v4l2_frequency vFrequency;

int radio_fd;
int mixer_fd;

unsigned int freq;
unsigned int vol;

boolean silent;
};
...
unsigned int FMOperations::radio_initTuner(RadioDescriptor* radioDesc){
//zero out the reserved words of the v4l_tuner struct
for(int resWords = 0; resWords < V4L2_RESERVED_SEGMENT_SIZE_TUNER; resWords++){
radioDesc->vTuner.reserved[resWords] = 0;
}

int tunerIndex = 0;
int gTunerRes = 0;
radioDesc->vTuner.index = tunerIndex;

gTunerRes = ioctl(radioDesc->radio_fd,VIDIOC_G_TUNER,&radioDesc->vTuner);
if(gTunerRes != EINVAL){
__android_log_print(ANDROID_LOG_VERBOSE,"FMOperations","fmdelver -- /dev/radio0 reports a tuner index %i",tunerIndex);
tunerIndex++;
}

}
unsigned int FMOperations::radio_setTunerPropertiesAndTune(RadioDescriptor* radioDesc,unsigned int audMode, float targetFrequency){
//zero out the reserved block in the v4l2_frequency struct
for(int resWords = 0; resWords < V4L2_RESERVED_SEGMENT_SIZE_FREQUENCY; resWords++){
radioDesc->vFrequency.reserved[resWords] = 0;
}

//set audio mode
radioDesc->vTuner.audmode = audMode;

//set the target tuner index whose freq we wish to change
radioDesc->vFrequency.tuner = radioDesc->vTuner.index;
radioDesc->vFrequency.type = V4L2_TUNER_RADIO;
radioDesc->vFrequency.frequency = rint(targetFrequency * 16 + 0.5);

//issue the ioctl to actually perform the frequency tune
int tuneStatus = ioctl(radioDesc->radio_fd,VIDIOC_S_FREQUENCY,&radioDesc->vFrequency);

if(tuneStatus < 0)
{
__android_log_print(ANDROID_LOG_VERBOSE,"FMOperations","fmdelver -- Failed to tune to frequency %d\n",radioDesc->vFrequency.frequency);
logStdErr("Failed to tune:");
return FM_FAILED;
}
__android_log_print(ANDROID_LOG_VERBOSE,"FMOperations","fmdelver -- Tuned to frequency %i KHz\n",radioDesc->vFrequency.frequency);

}

My main function creates an empty RadioDescriptor struct radioDesc, calls initTuner(&radioDesc) and then setTunerPropertiesAndTune(&radioDesc,V4L2_TUNER_MODE_MONO, 88.1). It isn't quite clear what format the frequency should take (V4L2 docs say frequency is expected to be in units of 62.5 kHz or 62.5 Hz if TUNER_CAP_LOW is set... not clear how my_frequency_in_khz/62.5 is supposed to fit in the uint32 v4l2_frequency.frequency attribute) but I've tried MHz, KHz, Hz, and even KHz/62.5; all failed to tune and set errno to 5 (I/O Error).

Does anyone know if the Qualcomm tavarua is fully v4l2 compliant and, if so, what might be causing my errno 5? If the tavarua is not v4l2 compliant, are there any public docs detailing the Qualcomm tavarua API? Any general advice regarding troubleshooting I/O errors in native applications and driver development would also be greatly appreciated!