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

pdaudiocf_irq.c (8570B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Driver for Sound Core PDAudioCF soundcard
      4 *
      5 * Copyright (c) 2003 by Jaroslav Kysela <perex@perex.cz>
      6 */
      7
      8#include <sound/core.h>
      9#include "pdaudiocf.h"
     10#include <sound/initval.h>
     11#include <asm/irq_regs.h>
     12
     13/*
     14 *
     15 */
     16irqreturn_t pdacf_interrupt(int irq, void *dev)
     17{
     18	struct snd_pdacf *chip = dev;
     19	unsigned short stat;
     20	bool wake_thread = false;
     21
     22	if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|
     23				  PDAUDIOCF_STAT_IS_CONFIGURED|
     24				  PDAUDIOCF_STAT_IS_SUSPENDED)) != PDAUDIOCF_STAT_IS_CONFIGURED)
     25		return IRQ_HANDLED;	/* IRQ_NONE here? */
     26
     27	stat = inw(chip->port + PDAUDIOCF_REG_ISR);
     28	if (stat & (PDAUDIOCF_IRQLVL|PDAUDIOCF_IRQOVR)) {
     29		if (stat & PDAUDIOCF_IRQOVR)	/* should never happen */
     30			snd_printk(KERN_ERR "PDAUDIOCF SRAM buffer overrun detected!\n");
     31		if (chip->pcm_substream)
     32			wake_thread = true;
     33		if (!(stat & PDAUDIOCF_IRQAKM))
     34			stat |= PDAUDIOCF_IRQAKM;	/* check rate */
     35	}
     36	if (get_irq_regs() != NULL)
     37		snd_ak4117_check_rate_and_errors(chip->ak4117, 0);
     38	return wake_thread ? IRQ_WAKE_THREAD : IRQ_HANDLED;
     39}
     40
     41static inline void pdacf_transfer_mono16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
     42{
     43	while (size-- > 0) {
     44		*dst++ = inw(rdp_port) ^ xor;
     45		inw(rdp_port);
     46	}
     47}
     48
     49static inline void pdacf_transfer_mono32(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
     50{
     51	register u16 val1, val2;
     52
     53	while (size-- > 0) {
     54		val1 = inw(rdp_port);
     55		val2 = inw(rdp_port);
     56		inw(rdp_port);
     57		*dst++ = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
     58	}
     59}
     60
     61static inline void pdacf_transfer_stereo16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
     62{
     63	while (size-- > 0) {
     64		*dst++ = inw(rdp_port) ^ xor;
     65		*dst++ = inw(rdp_port) ^ xor;
     66	}
     67}
     68
     69static inline void pdacf_transfer_stereo32(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
     70{
     71	register u16 val1, val2, val3;
     72
     73	while (size-- > 0) {
     74		val1 = inw(rdp_port);
     75		val2 = inw(rdp_port);
     76		val3 = inw(rdp_port);
     77		*dst++ = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
     78		*dst++ = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;
     79	}
     80}
     81
     82static inline void pdacf_transfer_mono16sw(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
     83{
     84	while (size-- > 0) {
     85		*dst++ = swab16(inw(rdp_port) ^ xor);
     86		inw(rdp_port);
     87	}
     88}
     89
     90static inline void pdacf_transfer_mono32sw(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
     91{
     92	register u16 val1, val2;
     93
     94	while (size-- > 0) {
     95		val1 = inw(rdp_port);
     96		val2 = inw(rdp_port);
     97		inw(rdp_port);
     98		*dst++ = swab32((((val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor);
     99	}
    100}
    101
    102static inline void pdacf_transfer_stereo16sw(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
    103{
    104	while (size-- > 0) {
    105		*dst++ = swab16(inw(rdp_port) ^ xor);
    106		*dst++ = swab16(inw(rdp_port) ^ xor);
    107	}
    108}
    109
    110static inline void pdacf_transfer_stereo32sw(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
    111{
    112	register u16 val1, val2, val3;
    113
    114	while (size-- > 0) {
    115		val1 = inw(rdp_port);
    116		val2 = inw(rdp_port);
    117		val3 = inw(rdp_port);
    118		*dst++ = swab32((((val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor);
    119		*dst++ = swab32((((u32)val3 << 16) | (val2 & 0xff00)) ^ xor);
    120	}
    121}
    122
    123static inline void pdacf_transfer_mono24le(u8 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
    124{
    125	register u16 val1, val2;
    126	register u32 xval1;
    127
    128	while (size-- > 0) {
    129		val1 = inw(rdp_port);
    130		val2 = inw(rdp_port);
    131		inw(rdp_port);
    132		xval1 = (((val2 & 0xff) << 8) | (val1 << 16)) ^ xor;
    133		*dst++ = (u8)(xval1 >> 8);
    134		*dst++ = (u8)(xval1 >> 16);
    135		*dst++ = (u8)(xval1 >> 24);
    136	}
    137}
    138
    139static inline void pdacf_transfer_mono24be(u8 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
    140{
    141	register u16 val1, val2;
    142	register u32 xval1;
    143
    144	while (size-- > 0) {
    145		val1 = inw(rdp_port);
    146		val2 = inw(rdp_port);
    147		inw(rdp_port);
    148		xval1 = (((val2 & 0xff) << 8) | (val1 << 16)) ^ xor;
    149		*dst++ = (u8)(xval1 >> 24);
    150		*dst++ = (u8)(xval1 >> 16);
    151		*dst++ = (u8)(xval1 >> 8);
    152	}
    153}
    154
    155static inline void pdacf_transfer_stereo24le(u8 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
    156{
    157	register u16 val1, val2, val3;
    158	register u32 xval1, xval2;
    159
    160	while (size-- > 0) {
    161		val1 = inw(rdp_port);
    162		val2 = inw(rdp_port);
    163		val3 = inw(rdp_port);
    164		xval1 = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
    165		xval2 = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;
    166		*dst++ = (u8)(xval1 >> 8);
    167		*dst++ = (u8)(xval1 >> 16);
    168		*dst++ = (u8)(xval1 >> 24);
    169		*dst++ = (u8)(xval2 >> 8);
    170		*dst++ = (u8)(xval2 >> 16);
    171		*dst++ = (u8)(xval2 >> 24);
    172	}
    173}
    174
    175static inline void pdacf_transfer_stereo24be(u8 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
    176{
    177	register u16 val1, val2, val3;
    178	register u32 xval1, xval2;
    179
    180	while (size-- > 0) {
    181		val1 = inw(rdp_port);
    182		val2 = inw(rdp_port);
    183		val3 = inw(rdp_port);
    184		xval1 = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
    185		xval2 = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;
    186		*dst++ = (u8)(xval1 >> 24);
    187		*dst++ = (u8)(xval1 >> 16);
    188		*dst++ = (u8)(xval1 >> 8);
    189		*dst++ = (u8)(xval2 >> 24);
    190		*dst++ = (u8)(xval2 >> 16);
    191		*dst++ = (u8)(xval2 >> 8);
    192	}
    193}
    194
    195static void pdacf_transfer(struct snd_pdacf *chip, unsigned int size, unsigned int off)
    196{
    197	unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;
    198	unsigned int xor = chip->pcm_xor;
    199
    200	if (chip->pcm_sample == 3) {
    201		if (chip->pcm_little) {
    202			if (chip->pcm_channels == 1) {
    203				pdacf_transfer_mono24le((char *)chip->pcm_area + (off * 3), xor, size, rdp_port);
    204			} else {
    205				pdacf_transfer_stereo24le((char *)chip->pcm_area + (off * 6), xor, size, rdp_port);
    206			}
    207		} else {
    208			if (chip->pcm_channels == 1) {
    209				pdacf_transfer_mono24be((char *)chip->pcm_area + (off * 3), xor, size, rdp_port);
    210			} else {
    211				pdacf_transfer_stereo24be((char *)chip->pcm_area + (off * 6), xor, size, rdp_port);
    212			}			
    213		}
    214		return;
    215	}
    216	if (chip->pcm_swab == 0) {
    217		if (chip->pcm_channels == 1) {
    218			if (chip->pcm_frame == 2) {
    219				pdacf_transfer_mono16((u16 *)chip->pcm_area + off, xor, size, rdp_port);
    220			} else {
    221				pdacf_transfer_mono32((u32 *)chip->pcm_area + off, xor, size, rdp_port);
    222			}
    223		} else {
    224			if (chip->pcm_frame == 2) {
    225				pdacf_transfer_stereo16((u16 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
    226			} else {
    227				pdacf_transfer_stereo32((u32 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
    228			}
    229		}
    230	} else {
    231		if (chip->pcm_channels == 1) {
    232			if (chip->pcm_frame == 2) {
    233				pdacf_transfer_mono16sw((u16 *)chip->pcm_area + off, xor, size, rdp_port);
    234			} else {
    235				pdacf_transfer_mono32sw((u32 *)chip->pcm_area + off, xor, size, rdp_port);
    236			}
    237		} else {
    238			if (chip->pcm_frame == 2) {
    239				pdacf_transfer_stereo16sw((u16 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
    240			} else {
    241				pdacf_transfer_stereo32sw((u32 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
    242			}
    243		}
    244	}
    245}
    246
    247irqreturn_t pdacf_threaded_irq(int irq, void *dev)
    248{
    249	struct snd_pdacf *chip = dev;
    250	int size, off, cont, rdp, wdp;
    251
    252	if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|PDAUDIOCF_STAT_IS_CONFIGURED)) != PDAUDIOCF_STAT_IS_CONFIGURED)
    253		return IRQ_HANDLED;
    254	
    255	if (chip->pcm_substream == NULL || chip->pcm_substream->runtime == NULL || !snd_pcm_running(chip->pcm_substream))
    256		return IRQ_HANDLED;
    257
    258	rdp = inw(chip->port + PDAUDIOCF_REG_RDP);
    259	wdp = inw(chip->port + PDAUDIOCF_REG_WDP);
    260	/* printk(KERN_DEBUG "TASKLET: rdp = %x, wdp = %x\n", rdp, wdp); */
    261	size = wdp - rdp;
    262	if (size < 0)
    263		size += 0x10000;
    264	if (size == 0)
    265		size = 0x10000;
    266	size /= chip->pcm_frame;
    267	if (size > 64)
    268		size -= 32;
    269
    270#if 0
    271	chip->pcm_hwptr += size;
    272	chip->pcm_hwptr %= chip->pcm_size;
    273	chip->pcm_tdone += size;
    274	if (chip->pcm_frame == 2) {
    275		unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;
    276		while (size-- > 0) {
    277			inw(rdp_port);
    278			inw(rdp_port);
    279		}
    280	} else {
    281		unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;
    282		while (size-- > 0) {
    283			inw(rdp_port);
    284			inw(rdp_port);
    285			inw(rdp_port);
    286		}
    287	}
    288#else
    289	off = chip->pcm_hwptr + chip->pcm_tdone;
    290	off %= chip->pcm_size;
    291	chip->pcm_tdone += size;
    292	while (size > 0) {
    293		cont = chip->pcm_size - off;
    294		if (cont > size)
    295			cont = size;
    296		pdacf_transfer(chip, cont, off);
    297		off += cont;
    298		off %= chip->pcm_size;
    299		size -= cont;
    300	}
    301#endif
    302	mutex_lock(&chip->reg_lock);
    303	while (chip->pcm_tdone >= chip->pcm_period) {
    304		chip->pcm_hwptr += chip->pcm_period;
    305		chip->pcm_hwptr %= chip->pcm_size;
    306		chip->pcm_tdone -= chip->pcm_period;
    307		mutex_unlock(&chip->reg_lock);
    308		snd_pcm_period_elapsed(chip->pcm_substream);
    309		mutex_lock(&chip->reg_lock);
    310	}
    311	mutex_unlock(&chip->reg_lock);
    312	return IRQ_HANDLED;
    313}