Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/media/test-drivers/vivid/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 7 kB image not shown  

Quelle  vivid-radio-rx.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * vivid-radio-rx.c - radio receiver support functions.
 *
 * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
 */


#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/videodev2.h>
#include <linux/v4l2-dv-timings.h>
#include <linux/sched/signal.h>

#include <media/v4l2-common.h>
#include <media/v4l2-event.h>
#include <media/v4l2-dv-timings.h>

#include "vivid-core.h"
#include "vivid-ctrls.h"
#include "vivid-radio-common.h"
#include "vivid-rds-gen.h"
#include "vivid-radio-rx.h"

ssize_t vivid_radio_rx_read(struct file *file, char __user *buf,
    size_t size, loff_t *offset)
{
 struct vivid_dev *dev = video_drvdata(file);
 struct v4l2_rds_data *data = dev->rds_gen.data;
 bool use_alternates;
 ktime_t timestamp;
 unsigned blk;
 int perc;
 int i;

 if (dev->radio_rx_rds_controls)
  return -EINVAL;
 if (size < sizeof(*data))
  return 0;
 size = sizeof(*data) * (size / sizeof(*data));

 if (mutex_lock_interruptible(&dev->mutex))
  return -ERESTARTSYS;
 if (dev->radio_rx_rds_owner &&
     file->private_data != dev->radio_rx_rds_owner) {
  mutex_unlock(&dev->mutex);
  return -EBUSY;
 }
 if (dev->radio_rx_rds_owner == NULL) {
  vivid_radio_rds_init(dev);
  dev->radio_rx_rds_owner = file->private_data;
 }

retry:
 timestamp = ktime_sub(ktime_get(), dev->radio_rds_init_time);
 blk = ktime_divns(timestamp, VIVID_RDS_NSEC_PER_BLK);
 use_alternates = (blk % VIVID_RDS_GEN_BLOCKS) & 1;

 if (dev->radio_rx_rds_last_block == 0 ||
     dev->radio_rx_rds_use_alternates != use_alternates) {
  dev->radio_rx_rds_use_alternates = use_alternates;
  /* Re-init the RDS generator */
  vivid_radio_rds_init(dev);
 }
 if (blk >= dev->radio_rx_rds_last_block + VIVID_RDS_GEN_BLOCKS)
  dev->radio_rx_rds_last_block = blk - VIVID_RDS_GEN_BLOCKS + 1;

 /*
 * No data is available if there hasn't been time to get new data,
 * or if the RDS receiver has been disabled, or if we use the data
 * from the RDS transmitter and that RDS transmitter has been disabled,
 * or if the signal quality is too weak.
 */

 if (blk == dev->radio_rx_rds_last_block || !dev->radio_rx_rds_enabled ||
     (dev->radio_rds_loop && !(dev->radio_tx_subchans & V4L2_TUNER_SUB_RDS)) ||
     abs(dev->radio_rx_sig_qual) > 200) {
  mutex_unlock(&dev->mutex);
  if (file->f_flags & O_NONBLOCK)
   return -EWOULDBLOCK;
  if (msleep_interruptible(20) && signal_pending(current))
   return -EINTR;
  if (mutex_lock_interruptible(&dev->mutex))
   return -ERESTARTSYS;
  goto retry;
 }

 /* abs(dev->radio_rx_sig_qual) <= 200, map that to a 0-50% range */
 perc = abs(dev->radio_rx_sig_qual) / 4;

 for (i = 0; i < size && blk > dev->radio_rx_rds_last_block;
   dev->radio_rx_rds_last_block++) {
  unsigned data_blk = dev->radio_rx_rds_last_block % VIVID_RDS_GEN_BLOCKS;
  struct v4l2_rds_data rds = data[data_blk];

  if (data_blk == 0 && dev->radio_rds_loop)
   vivid_radio_rds_init(dev);
  if (perc && get_random_u32_below(100) < perc) {
   switch (get_random_u32_below(4)) {
   case 0:
    rds.block |= V4L2_RDS_BLOCK_CORRECTED;
    break;
   case 1:
    rds.block |= V4L2_RDS_BLOCK_INVALID;
    break;
   case 2:
    rds.block |= V4L2_RDS_BLOCK_ERROR;
    rds.lsb = get_random_u8();
    rds.msb = get_random_u8();
    break;
   case 3: /* Skip block altogether */
    if (i)
     continue;
    /*
 * Must make sure at least one block is
 * returned, otherwise the application
 * might think that end-of-file occurred.
 */

    break;
   }
  }
  if (copy_to_user(buf + i, &rds, sizeof(rds))) {
   i = -EFAULT;
   break;
  }
  i += sizeof(rds);
 }
 mutex_unlock(&dev->mutex);
 return i;
}

__poll_t vivid_radio_rx_poll(struct file *file, struct poll_table_struct *wait)
{
 return EPOLLIN | EPOLLRDNORM | v4l2_ctrl_poll(file, wait);
}

int vivid_radio_rx_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band)
{
 if (band->tuner != 0)
  return -EINVAL;

 if (band->index >= TOT_BANDS)
  return -EINVAL;

 *band = vivid_radio_bands[band->index];
 return 0;
}

int vivid_radio_rx_s_hw_freq_seek(struct file *file, void *fh, const struct v4l2_hw_freq_seek *a)
{
 struct vivid_dev *dev = video_drvdata(file);
 unsigned low, high;
 unsigned freq;
 unsigned spacing;
 unsigned band;

 if (a->tuner)
  return -EINVAL;
 if (a->wrap_around && dev->radio_rx_hw_seek_mode == VIVID_HW_SEEK_BOUNDED)
  return -EINVAL;

 if (!a->wrap_around && dev->radio_rx_hw_seek_mode == VIVID_HW_SEEK_WRAP)
  return -EINVAL;
 if (!a->rangelow ^ !a->rangehigh)
  return -EINVAL;

 if (file->f_flags & O_NONBLOCK)
  return -EWOULDBLOCK;

 if (a->rangelow) {
  for (band = 0; band < TOT_BANDS; band++)
   if (a->rangelow >= vivid_radio_bands[band].rangelow &&
       a->rangehigh <= vivid_radio_bands[band].rangehigh)
    break;
  if (band == TOT_BANDS)
   return -EINVAL;
  if (!dev->radio_rx_hw_seek_prog_lim &&
      (a->rangelow != vivid_radio_bands[band].rangelow ||
       a->rangehigh != vivid_radio_bands[band].rangehigh))
   return -EINVAL;
  low = a->rangelow;
  high = a->rangehigh;
 } else {
  for (band = 0; band < TOT_BANDS; band++)
   if (dev->radio_rx_freq >= vivid_radio_bands[band].rangelow &&
       dev->radio_rx_freq <= vivid_radio_bands[band].rangehigh)
    break;
  if (band == TOT_BANDS)
   return -EINVAL;
  low = vivid_radio_bands[band].rangelow;
  high = vivid_radio_bands[band].rangehigh;
 }
 spacing = band == BAND_AM ? 1600 : 16000;
 freq = clamp(dev->radio_rx_freq, low, high);

 if (a->seek_upward) {
  freq = spacing * (freq / spacing) + spacing;
  if (freq > high) {
   if (!a->wrap_around)
    return -ENODATA;
   freq = spacing * (low / spacing) + spacing;
   if (freq >= dev->radio_rx_freq)
    return -ENODATA;
  }
 } else {
  freq = spacing * ((freq + spacing - 1) / spacing) - spacing;
  if (freq < low) {
   if (!a->wrap_around)
    return -ENODATA;
   freq = spacing * ((high + spacing - 1) / spacing) - spacing;
   if (freq <= dev->radio_rx_freq)
    return -ENODATA;
  }
 }
 return 0;
}

int vivid_radio_rx_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
{
 struct vivid_dev *dev = video_drvdata(file);
 int delta = 800;
 int sig_qual;

 if (vt->index > 0)
  return -EINVAL;

 strscpy(vt->name, "AM/FM/SW Receiver"sizeof(vt->name));
 vt->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
    V4L2_TUNER_CAP_FREQ_BANDS | V4L2_TUNER_CAP_RDS |
    (dev->radio_rx_rds_controls ?
    V4L2_TUNER_CAP_RDS_CONTROLS :
    V4L2_TUNER_CAP_RDS_BLOCK_IO) |
    (dev->radio_rx_hw_seek_prog_lim ?
    V4L2_TUNER_CAP_HWSEEK_PROG_LIM : 0);
 switch (dev->radio_rx_hw_seek_mode) {
 case VIVID_HW_SEEK_BOUNDED:
  vt->capability |= V4L2_TUNER_CAP_HWSEEK_BOUNDED;
  break;
 case VIVID_HW_SEEK_WRAP:
  vt->capability |= V4L2_TUNER_CAP_HWSEEK_WRAP;
  break;
 case VIVID_HW_SEEK_BOTH:
  vt->capability |= V4L2_TUNER_CAP_HWSEEK_WRAP |
      V4L2_TUNER_CAP_HWSEEK_BOUNDED;
  break;
 }
 vt->rangelow = AM_FREQ_RANGE_LOW;
 vt->rangehigh = FM_FREQ_RANGE_HIGH;
 sig_qual = dev->radio_rx_sig_qual;
 vt->signal = abs(sig_qual) > delta ? 0 :
       0xffff - ((unsigned)abs(sig_qual) * 0xffff) / delta;
 vt->afc = sig_qual > delta ? 0 : sig_qual;
 if (abs(sig_qual) > delta)
  vt->rxsubchans = 0;
 else if (dev->radio_rx_freq < FM_FREQ_RANGE_LOW || vt->signal < 0x8000)
  vt->rxsubchans = V4L2_TUNER_SUB_MONO;
 else if (dev->radio_rds_loop && !(dev->radio_tx_subchans & V4L2_TUNER_SUB_STEREO))
  vt->rxsubchans = V4L2_TUNER_SUB_MONO;
 else
  vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
 if (dev->radio_rx_rds_enabled &&
     (!dev->radio_rds_loop || (dev->radio_tx_subchans & V4L2_TUNER_SUB_RDS)) &&
     dev->radio_rx_freq >= FM_FREQ_RANGE_LOW && vt->signal >= 0xc000)
  vt->rxsubchans |= V4L2_TUNER_SUB_RDS;
 if (dev->radio_rx_rds_controls)
  vivid_radio_rds_init(dev);
 vt->audmode = dev->radio_rx_audmode;
 return 0;
}

int vivid_radio_rx_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt)
{
 struct vivid_dev *dev = video_drvdata(file);

 if (vt->index)
  return -EINVAL;
 dev->radio_rx_audmode = vt->audmode >= V4L2_TUNER_MODE_STEREO;
 return 0;
}

Messung V0.5
C=98 H=98 G=97

¤ Dauer der Verarbeitung: 0.1 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.