drivers/media/test-drivers/vivid/vivid-radio-rx.c

Source file repositories/reference/linux-study-clean/drivers/media/test-drivers/vivid/vivid-radio-rx.c

File Facts

System
Linux kernel
Corpus path
drivers/media/test-drivers/vivid/vivid-radio-rx.c
Extension
.c
Size
8101 bytes
Lines
279
Domain
Driver Families
Bucket
drivers/media
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

file_to_v4l2_fh(file) != 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_to_v4l2_fh(file);
	}

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);
}

Annotation

Implementation Notes