cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vivid-rds-gen.c (4696B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * vivid-rds-gen.c - rds (radio data system) generator support functions.
      4 *
      5 * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
      6 */
      7
      8#include <linux/kernel.h>
      9#include <linux/ktime.h>
     10#include <linux/string.h>
     11#include <linux/videodev2.h>
     12
     13#include "vivid-rds-gen.h"
     14
     15static u8 vivid_get_di(const struct vivid_rds_gen *rds, unsigned grp)
     16{
     17	switch (grp) {
     18	case 0:
     19		return (rds->dyn_pty << 2) | (grp & 3);
     20	case 1:
     21		return (rds->compressed << 2) | (grp & 3);
     22	case 2:
     23		return (rds->art_head << 2) | (grp & 3);
     24	case 3:
     25		return (rds->mono_stereo << 2) | (grp & 3);
     26	}
     27	return 0;
     28}
     29
     30/*
     31 * This RDS generator creates 57 RDS groups (one group == four RDS blocks).
     32 * Groups 0-3, 22-25 and 44-47 (spaced 22 groups apart) are filled with a
     33 * standard 0B group containing the PI code and PS name.
     34 *
     35 * Groups 4-19 and 26-41 use group 2A for the radio text.
     36 *
     37 * Group 56 contains the time (group 4A).
     38 *
     39 * All remaining groups use a filler group 15B block that just repeats
     40 * the PI and PTY codes.
     41 */
     42void vivid_rds_generate(struct vivid_rds_gen *rds)
     43{
     44	struct v4l2_rds_data *data = rds->data;
     45	unsigned grp;
     46	unsigned idx;
     47	struct tm tm;
     48	unsigned date;
     49	unsigned time;
     50	int l;
     51
     52	for (grp = 0; grp < VIVID_RDS_GEN_GROUPS; grp++, data += VIVID_RDS_GEN_BLKS_PER_GRP) {
     53		data[0].lsb = rds->picode & 0xff;
     54		data[0].msb = rds->picode >> 8;
     55		data[0].block = V4L2_RDS_BLOCK_A | (V4L2_RDS_BLOCK_A << 3);
     56		data[1].lsb = rds->pty << 5;
     57		data[1].msb = (rds->pty >> 3) | (rds->tp << 2);
     58		data[1].block = V4L2_RDS_BLOCK_B | (V4L2_RDS_BLOCK_B << 3);
     59		data[3].block = V4L2_RDS_BLOCK_D | (V4L2_RDS_BLOCK_D << 3);
     60
     61		switch (grp) {
     62		case 0 ... 3:
     63		case 22 ... 25:
     64		case 44 ... 47: /* Group 0B */
     65			idx = (grp % 22) % 4;
     66			data[1].lsb |= (rds->ta << 4) | (rds->ms << 3);
     67			data[1].lsb |= vivid_get_di(rds, idx);
     68			data[1].msb |= 1 << 3;
     69			data[2].lsb = rds->picode & 0xff;
     70			data[2].msb = rds->picode >> 8;
     71			data[2].block = V4L2_RDS_BLOCK_C_ALT | (V4L2_RDS_BLOCK_C_ALT << 3);
     72			data[3].lsb = rds->psname[2 * idx + 1];
     73			data[3].msb = rds->psname[2 * idx];
     74			break;
     75		case 4 ... 19:
     76		case 26 ... 41: /* Group 2A */
     77			idx = ((grp - 4) % 22) % 16;
     78			data[1].lsb |= idx;
     79			data[1].msb |= 4 << 3;
     80			data[2].msb = rds->radiotext[4 * idx];
     81			data[2].lsb = rds->radiotext[4 * idx + 1];
     82			data[2].block = V4L2_RDS_BLOCK_C | (V4L2_RDS_BLOCK_C << 3);
     83			data[3].msb = rds->radiotext[4 * idx + 2];
     84			data[3].lsb = rds->radiotext[4 * idx + 3];
     85			break;
     86		case 56:
     87			/*
     88			 * Group 4A
     89			 *
     90			 * Uses the algorithm from Annex G of the RDS standard
     91			 * EN 50067:1998 to convert a UTC date to an RDS Modified
     92			 * Julian Day.
     93			 */
     94			time64_to_tm(ktime_get_real_seconds(), 0, &tm);
     95			l = tm.tm_mon <= 1;
     96			date = 14956 + tm.tm_mday + ((tm.tm_year - l) * 1461) / 4 +
     97				((tm.tm_mon + 2 + l * 12) * 306001) / 10000;
     98			time = (tm.tm_hour << 12) |
     99			       (tm.tm_min << 6) |
    100			       (sys_tz.tz_minuteswest >= 0 ? 0x20 : 0) |
    101			       (abs(sys_tz.tz_minuteswest) / 30);
    102			data[1].lsb &= ~3;
    103			data[1].lsb |= date >> 15;
    104			data[1].msb |= 8 << 3;
    105			data[2].lsb = (date << 1) & 0xfe;
    106			data[2].lsb |= (time >> 16) & 1;
    107			data[2].msb = (date >> 7) & 0xff;
    108			data[2].block = V4L2_RDS_BLOCK_C | (V4L2_RDS_BLOCK_C << 3);
    109			data[3].lsb = time & 0xff;
    110			data[3].msb = (time >> 8) & 0xff;
    111			break;
    112		default: /* Group 15B */
    113			data[1].lsb |= (rds->ta << 4) | (rds->ms << 3);
    114			data[1].lsb |= vivid_get_di(rds, grp % 22);
    115			data[1].msb |= 0x1f << 3;
    116			data[2].lsb = rds->picode & 0xff;
    117			data[2].msb = rds->picode >> 8;
    118			data[2].block = V4L2_RDS_BLOCK_C_ALT | (V4L2_RDS_BLOCK_C_ALT << 3);
    119			data[3].lsb = rds->pty << 5;
    120			data[3].lsb |= (rds->ta << 4) | (rds->ms << 3);
    121			data[3].lsb |= vivid_get_di(rds, grp % 22);
    122			data[3].msb |= rds->pty >> 3;
    123			data[3].msb |= 0x1f << 3;
    124			break;
    125		}
    126	}
    127}
    128
    129void vivid_rds_gen_fill(struct vivid_rds_gen *rds, unsigned freq,
    130			  bool alt)
    131{
    132	/* Alternate PTY between Info and Weather */
    133	if (rds->use_rbds) {
    134		rds->picode = 0x2e75; /* 'KLNX' call sign */
    135		rds->pty = alt ? 29 : 2;
    136	} else {
    137		rds->picode = 0x8088;
    138		rds->pty = alt ? 16 : 3;
    139	}
    140	rds->mono_stereo = true;
    141	rds->art_head = false;
    142	rds->compressed = false;
    143	rds->dyn_pty = false;
    144	rds->tp = true;
    145	rds->ta = alt;
    146	rds->ms = true;
    147	snprintf(rds->psname, sizeof(rds->psname), "%6d.%1d",
    148		 freq / 16, ((freq & 0xf) * 10) / 16);
    149	if (alt)
    150		strscpy(rds->radiotext,
    151			" The Radio Data System can switch between different Radio Texts ",
    152			sizeof(rds->radiotext));
    153	else
    154		strscpy(rds->radiotext,
    155			"An example of Radio Text as transmitted by the Radio Data System",
    156			sizeof(rds->radiotext));
    157}