/* Read RDS data */ static ssize_t fm_v4l2_fops_read(struct file *file, char __user * buf, size_t count, loff_t *ppos) { unsigned char rds_mode; int ret, noof_bytes_copied; FMDRV_API_START(); if (!radio_disconnected) { FM_DRV_ERR("FM device is already disconnected\n"); FMDRV_API_EXIT(-EIO); return -EIO; } /* Turn on RDS mode , if it is disabled */ ret = fm_core_rx_get_rds_mode(&rds_mode); if (ret) { FM_DRV_ERR("Unable to read current rds mode"); FMDRV_API_EXIT(ret); return ret; } if (rds_mode == FM_RX_RDS_DISABLE) { ret = fm_core_set_rds_mode(FM_RX_RDS_ENABLE); if (ret < 0) { FM_DRV_ERR("Unable to enable rds mode"); FMDRV_API_EXIT(ret); return ret; } } /* Copy RDS data from internal buffer to user buffer */ noof_bytes_copied = fm_core_transfer_rds_from_internal_buff(file, buf, count); FMDRV_API_EXIT(noof_bytes_copied); return noof_bytes_copied; }
/* Forwards FM Packets to Shared Transport */ int fm_st_send(struct sk_buff *skb) { long len; FMDRV_API_START(); if (skb == NULL) { FM_DRV_ERR("Invalid skb, can't send"); FMDRV_API_EXIT(-ENOMEM); return -ENOMEM; } /* Is anyone called without claiming FM ST? */ if (is_fm_st_claimed == FM_ST_CLAIMED ) { /* Forward FM packet(SKB) to ST for the transmission */ len = st_write(skb); if (len < 0) { /* Something went wrong in st write , free skb memory */ kfree_skb(skb); FM_DRV_ERR(" ST write failed (%ld)", len); FMDRV_API_EXIT(-EAGAIN); return -EAGAIN; } } else { /* Nobody calimed FM ST */ kfree_skb(skb); FM_DRV_ERR("FM ST is not claimed, Can't send skb"); FMDRV_API_EXIT(-EAGAIN); return -EAGAIN; } FMDRV_API_EXIT(0); return 0; }
int fm_v4l2_init_video_device(struct fmdrv_ops *fmdev) { FMDRV_API_START(); /* Allocate new video device */ fmdev->v4l2dev = video_device_alloc(); if (!fmdev->v4l2dev) { FM_DRV_ERR("Can't allocate video device"); FMDRV_API_EXIT(-ENOMEM); return -ENOMEM; } /* Setup FM driver's V4L2 properties */ memcpy(fmdev->v4l2dev, &fm_viddev_template, sizeof(fm_viddev_template)); video_set_drvdata(fmdev->v4l2dev, fmdev); /* Register with V4L2 subsystem as RADIO device */ if (video_register_device(fmdev->v4l2dev, VFL_TYPE_RADIO, 0)) { video_device_release(fmdev->v4l2dev); fmdev->v4l2dev = NULL; FM_DRV_ERR("Could not register video device"); FMDRV_API_EXIT(-ENOMEM); return -ENOMEM; } FMDRV_API_EXIT(0); return 0; }
/* Set the value of a control */ static int fm_v4l2_vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { int ret; FMDRV_API_START(); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: /* set mute */ ret = fm_core_set_mute_mode((unsigned char)ctrl->value); if (ret < 0) { FMDRV_API_EXIT(ret); return ret; } break; case V4L2_CID_AUDIO_VOLUME: /* set volume */ ret = fm_core_rx_set_volume((unsigned short)ctrl->value); if (ret < 0) { FMDRV_API_EXIT(ret); return ret; } break; } FMDRV_API_EXIT(0); return 0; }
/* Set tuner attributes */ static int fm_v4l2_vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *tuner) { unsigned short mode; int ret; FMDRV_API_START(); if ((tuner->index != 0) || (tuner->audmode != V4L2_TUNER_MODE_MONO && tuner->audmode != V4L2_TUNER_MODE_STEREO)) { FMDRV_API_EXIT(-EINVAL); return -EINVAL; } /* Map V4L2 stereo/mono macro to our local stereo/mono macro */ mode = (tuner->audmode == V4L2_TUNER_MODE_STEREO) ? FM_STEREO_MODE : FM_MONO_MODE; ret = fm_core_set_stereo_mono(mode); if (ret) { FMDRV_API_EXIT(ret); return ret; } FMDRV_API_EXIT(0); return 0; }
/* Get the value of a control */ static int fm_v4l2_vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { int ret; unsigned short curr_vol; unsigned char curr_mute_mode; FMDRV_API_START(); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: /* get mute mode */ ret = fm_core_rx_get_mute_mode(&curr_mute_mode); if (ret < 0) { FMDRV_API_EXIT(ret); return ret; } ctrl->value = curr_mute_mode; break; case V4L2_CID_AUDIO_VOLUME: /* get volume */ ret = fm_core_rx_get_volume(&curr_vol); if (ret < 0) { FMDRV_API_EXIT(ret); return ret; } ctrl->value = curr_vol; break; } FMDRV_API_EXIT(0); return 0; }
/* Get tuner attributes */ static int fm_v4l2_vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *tuner) { unsigned int bottom_frequency; unsigned int top_frequency; unsigned short stereo_mono_mode; unsigned short rssilvl; int ret; FMDRV_API_START(); if (tuner->index != 0) { FMDRV_API_EXIT(-EINVAL); return -EINVAL; } ret = fm_core_rx_get_currband_lowhigh_freq(&bottom_frequency, &top_frequency); if (ret) { FMDRV_API_EXIT(ret); return ret; } ret = fm_core_rx_get_stereo_mono(&stereo_mono_mode); if (ret) { FMDRV_API_EXIT(ret); return ret; } ret = fm_core_rx_get_rssi_level(&rssilvl); if (ret) { FMDRV_API_EXIT(ret); return ret; } strcpy(tuner->name, "FM"); tuner->type = V4L2_TUNER_RADIO; /* Store rangelow and rangehigh freq in unit of 62.5 KHz */ tuner->rangelow = (bottom_frequency * 10000) / 625; tuner->rangehigh = (top_frequency * 10000) / 625; tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; tuner->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW; tuner->audmode = (stereo_mono_mode ? V4L2_TUNER_MODE_MONO : V4L2_TUNER_MODE_STEREO); /* Actual rssi value lies in between -128 to +127. * Convert this range from 0 to 255 by adding +128 */ rssilvl += 128; /* Return signal strength value should be within 0 to 65535. * Find out correct signal radio by multiplying (65535/255) = 257 */ tuner->signal = rssilvl * 257; tuner->afc = 0; FMDRV_API_EXIT(0); return 0; }
/* Set audio attributes */ static int fm_v4l2_vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *audio) { FMDRV_API_START(); if (audio->index != 0) { FMDRV_API_EXIT(-EINVAL); return -EINVAL; } FMDRV_API_EXIT(0); return 0; }
/* Set tuner or modulator radio frequency */ static int fm_v4l2_vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *freq) { int ret; FMDRV_API_START(); ret = fm_core_set_frequency(freq->frequency); if (ret) { FMDRV_API_EXIT(ret); return ret; } FMDRV_API_EXIT(0); return 0; }
/* Poll RDS data */ static unsigned int fm_v4l2_fops_poll(struct file *file, struct poll_table_struct *pts) { int ret; FMDRV_API_START(); ret = fm_core_is_rds_data_available(file, pts); if (!ret) { FMDRV_API_EXIT(POLLIN | POLLRDNORM); return POLLIN | POLLRDNORM; } FMDRV_API_EXIT(0); return 0; }
/* Set hardware frequency seek */ static int fm_v4l2_vidioc_s_hw_freq_seek(struct file *file, void *priv, struct v4l2_hw_freq_seek *seek) { int ret; FMDRV_API_START(); ret = fm_core_rx_seek(seek->seek_upward, seek->wrap_around); if (ret) { FMDRV_API_EXIT(ret); return ret; } FMDRV_API_EXIT(0); return 0; }
static int fm_mixer_rx_rds_opmode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { unsigned char rds_mode; int ret; FMDRV_API_START(); ret = fm_core_rx_get_rds_system(&rds_mode); if (ret) { FMDRV_API_EXIT(ret); return ret; } ucontrol->value.enumerated.item[0] = rds_mode & 0x1; FMDRV_API_EXIT(0); return 0; }
static int fm_mixer_rx_deemphasis_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { unsigned short mode; int ret; FMDRV_API_START(); ret = fm_core_rx_get_deemphasis_mode(&mode); if (ret) { FMDRV_API_EXIT(ret); return ret; } ucontrol->value.enumerated.item[0] = mode & 0x1; FMDRV_API_EXIT(0); return 0; }
static int fm_mixer_region_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { unsigned char region; int ret; FMDRV_API_START(); ret = fm_core_region_get(®ion); if (ret) { FMDRV_API_EXIT(ret); return ret; } ucontrol->value.enumerated.item[0] = region & 0x1; FMDRV_API_EXIT(0); return 0; }
/* Called from FM Core and FM Char device interface to claim * FM ST. Who ever comes first, ownership of FM ST will be * given to them. */ int fm_st_claim(void) { FMDRV_API_START(); /* Give ownership of FM ST to first caller */ if (is_fm_st_claimed == FM_ST_NOT_CLAIMED) { is_fm_st_claimed = FM_ST_CLAIMED; FMDRV_API_EXIT(FM_ST_SUCCESS); return FM_ST_SUCCESS; } FM_DRV_DBG("FM ST claimed already"); FMDRV_API_EXIT(FM_ST_FAILED); return FM_ST_FAILED; }
int fm_mixer_init(struct fmdrv_ops *fmdev) { int idx; int ret; FMDRV_API_START(); /* Allocate new card for FM driver */ fmdev->card = snd_card_new(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, THIS_MODULE, 0); if (!fmdev->card) { FM_DRV_ERR("No memory to allocate new card"); FMDRV_API_EXIT(-ENOMEM); return -ENOMEM; } fmdev->card->private_data = fmdev; /* Add FM mixer controls to the card */ strcpy(fmdev->card->mixername, FM_DRV_MIXER_NAME); for (idx = 0; idx < ARRAY_SIZE(snd_fm_controls); idx++) { ret = snd_ctl_add(fmdev->card, snd_ctl_new1(&snd_fm_controls[idx], fmdev)); if (ret < 0) { snd_card_free(fmdev->card); FM_DRV_ERR("Failed to add mixer controls"); FMDRV_API_EXIT(ret); return ret; } } /* Register FM card with ALSA */ ret = snd_card_register(fmdev->card); if (ret) { snd_card_free(fmdev->card); FM_DRV_ERR("Failed to register new card"); FMDRV_API_EXIT(ret); return ret; } strcpy(fmdev->card->driver, FM_DRV_NAME); strcpy(fmdev->card->shortname, FM_DRV_CARD_SHORT_NAME); sprintf(fmdev->card->longname, FM_DRV_CARD_LONG_NAME); FMDRV_API_EXIT(0); return 0; }
static int fm_mixer_rx_af_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { unsigned char af_mode; int ret; FMDRV_API_START(); ret = fm_core_rx_get_af_switch(&af_mode); if (ret) { FMDRV_API_EXIT(ret); return ret; } ucontrol->value.enumerated.item[0] = af_mode & 0x1; FMDRV_API_EXIT(0); return 0; }
static int fm_mixer_rfdepend_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { unsigned char en_dis; int ret; FMDRV_API_START(); ret = fm_core_rx_get_rfdepend_softmute(&en_dis); if (ret) { FMDRV_API_EXIT(ret); return ret; } ucontrol->value.enumerated.item[0] = en_dis & 0x1; FMDRV_API_EXIT(0); return 0; }
static int fm_mixer_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int ret; unsigned char current_fmmode; FMDRV_API_START(); ret = fm_core_mode_get(¤t_fmmode); if (ret) { FMDRV_API_EXIT(ret); return ret; } ucontrol->value.enumerated.item[0] = current_fmmode & 3; FMDRV_API_EXIT(0); return 0; }
static int fm_mixer_rx_rssi_threshold_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { short curr_rssi_threshold; int ret; FMDRV_API_START(); ret = fm_core_rx_get_rssi_threshold(&curr_rssi_threshold); if (ret) { FMDRV_API_EXIT(ret); return ret; } ucontrol->value.integer.value[0] = curr_rssi_threshold; FMDRV_API_EXIT(0); return 0; }
/* Called from FM Core and FM Char device interface * to release FM ST. */ int fm_st_release(void) { FMDRV_API_START(); /* Release FM ST if it is already claimed */ if (is_fm_st_claimed == FM_ST_CLAIMED) { is_fm_st_claimed = FM_ST_NOT_CLAIMED; FMDRV_API_EXIT(FM_ST_SUCCESS); return FM_ST_SUCCESS; } FM_DRV_ERR("FM ST is not claimed,called again?"); FMDRV_API_EXIT(FM_ST_FAILED); return FM_ST_FAILED; }
int fm_mixer_deinit(struct fmdrv_ops *fmdev) { FMDRV_API_START(); /* Unregister FM card from ALSA */ snd_card_free(fmdev->card); FMDRV_API_EXIT(0); return 0; }
static int fm_mixer_rx_af_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { unsigned char af_mode; int changed, ret; FMDRV_API_START(); af_mode = ucontrol->value.integer.value[0] & 0x1; ret = fm_core_rx_set_af_switch(af_mode); if (ret) { FMDRV_API_EXIT(ret); return ret; } changed = 1; FMDRV_API_EXIT(changed); return changed; }
int fm_v4l2_deinit_video_device(struct fmdrv_ops *fmdev) { FMDRV_API_START(); /* Unregister RADIO device from V4L2 subsystem */ video_unregister_device(fmdev->v4l2dev); FMDRV_API_EXIT(0); return 0; }
static int fm_mixer_rfdepend_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { unsigned char en_dis; int changed, ret; FMDRV_API_START(); en_dis = ucontrol->value.integer.value[0] & 0x1; ret = fm_core_rx_set_rfdepend_softmute(en_dis); if (ret) { FMDRV_API_EXIT(ret); return ret; } changed = 1; FMDRV_API_EXIT(changed); return changed; }
/* File Open */ static int fm_v4l2_fops_open(struct file *file) { int ret; FMDRV_API_START(); /* Don't allow multiple open */ if (radio_disconnected) { FM_DRV_ERR("FM device is already opened\n"); FMDRV_API_EXIT(-EBUSY); return -EBUSY; } /* Request FM Core to link with FM ST */ ret = fm_core_setup_transport(); if (ret) { FM_DRV_ERR("Unable to setup FM Core transport"); FMDRV_API_EXIT(ret); return ret; } /* Initialize FM Core */ ret = fm_core_prepare(); if (ret) { FM_DRV_ERR("Unable to prepare FM CORE"); FMDRV_API_EXIT(ret); return ret; } FM_DRV_DBG("Load FM RX firmware.."); /* By default load FM RX firmware */ ret = fm_core_mode_set(FM_MODE_RX); if (ret) { FM_DRV_ERR("Unable to load FM RX firmware"); FMDRV_API_EXIT(ret); return ret; } radio_disconnected = 1; FM_DRV_DBG("FM CORE is ready"); FMDRV_API_EXIT(0); return 0; }
static int fm_mixer_rx_rds_opmode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int ret; unsigned char rds_mode; int changed; FMDRV_API_START(); rds_mode = ucontrol->value.integer.value[0] & 0x1; ret = fm_core_rx_set_rds_system(rds_mode); if (ret) { FMDRV_API_EXIT(ret); return ret; } changed = 1; FMDRV_API_EXIT(changed); return changed; }
static int fm_mixer_rx_deemphasis_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int ret; unsigned short mode; int changed; FMDRV_API_START(); mode = ucontrol->value.integer.value[0] & 0x1; ret = fm_core_rx_set_deemphasis_mode(mode); if (ret) { FMDRV_API_EXIT(ret); return ret; } changed = 1; FMDRV_API_EXIT(changed); return changed; }
static int fm_mixer_region_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { int ret; unsigned char region; int changed; FMDRV_API_START(); region = ucontrol->value.integer.value[0] & 0x1; ret = fm_core_region_set(region); if (ret) { FMDRV_API_EXIT(ret); return ret; } changed = 1; FMDRV_API_EXIT(changed); return changed; }
/* Unregister FM Driver from Shared Transport */ int fm_st_unregister(void) { int ret; FMDRV_API_START(); /* Unregister FM Driver from ST */ ret = st_unregister(8); if (ret != ST_SUCCESS) { FM_DRV_ERR("st_unregister failed %d", ret); FMDRV_API_EXIT(-EBUSY); return -EBUSY; } g_rx_task = NULL; g_rx_q = NULL; FMDRV_API_EXIT(0); return 0; }