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

seq_oss_writeq.c (3499B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * OSS compatible sequencer driver
      4 *
      5 * seq_oss_writeq.c - write queue and sync
      6 *
      7 * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
      8 */
      9
     10#include "seq_oss_writeq.h"
     11#include "seq_oss_event.h"
     12#include "seq_oss_timer.h"
     13#include <sound/seq_oss_legacy.h>
     14#include "../seq_lock.h"
     15#include "../seq_clientmgr.h"
     16#include <linux/wait.h>
     17#include <linux/slab.h>
     18#include <linux/sched/signal.h>
     19
     20
     21/*
     22 * create a write queue record
     23 */
     24struct seq_oss_writeq *
     25snd_seq_oss_writeq_new(struct seq_oss_devinfo *dp, int maxlen)
     26{
     27	struct seq_oss_writeq *q;
     28	struct snd_seq_client_pool pool;
     29
     30	q = kzalloc(sizeof(*q), GFP_KERNEL);
     31	if (!q)
     32		return NULL;
     33	q->dp = dp;
     34	q->maxlen = maxlen;
     35	spin_lock_init(&q->sync_lock);
     36	q->sync_event_put = 0;
     37	q->sync_time = 0;
     38	init_waitqueue_head(&q->sync_sleep);
     39
     40	memset(&pool, 0, sizeof(pool));
     41	pool.client = dp->cseq;
     42	pool.output_pool = maxlen;
     43	pool.output_room = maxlen / 2;
     44
     45	snd_seq_oss_control(dp, SNDRV_SEQ_IOCTL_SET_CLIENT_POOL, &pool);
     46
     47	return q;
     48}
     49
     50/*
     51 * delete the write queue
     52 */
     53void
     54snd_seq_oss_writeq_delete(struct seq_oss_writeq *q)
     55{
     56	if (q) {
     57		snd_seq_oss_writeq_clear(q);	/* to be sure */
     58		kfree(q);
     59	}
     60}
     61
     62
     63/*
     64 * reset the write queue
     65 */
     66void
     67snd_seq_oss_writeq_clear(struct seq_oss_writeq *q)
     68{
     69	struct snd_seq_remove_events reset;
     70
     71	memset(&reset, 0, sizeof(reset));
     72	reset.remove_mode = SNDRV_SEQ_REMOVE_OUTPUT; /* remove all */
     73	snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_REMOVE_EVENTS, &reset);
     74
     75	/* wake up sleepers if any */
     76	snd_seq_oss_writeq_wakeup(q, 0);
     77}
     78
     79/*
     80 * wait until the write buffer has enough room
     81 */
     82int
     83snd_seq_oss_writeq_sync(struct seq_oss_writeq *q)
     84{
     85	struct seq_oss_devinfo *dp = q->dp;
     86	abstime_t time;
     87
     88	time = snd_seq_oss_timer_cur_tick(dp->timer);
     89	if (q->sync_time >= time)
     90		return 0; /* already finished */
     91
     92	if (! q->sync_event_put) {
     93		struct snd_seq_event ev;
     94		union evrec *rec;
     95
     96		/* put echoback event */
     97		memset(&ev, 0, sizeof(ev));
     98		ev.flags = 0;
     99		ev.type = SNDRV_SEQ_EVENT_ECHO;
    100		ev.time.tick = time;
    101		/* echo back to itself */
    102		snd_seq_oss_fill_addr(dp, &ev, dp->addr.client, dp->addr.port);
    103		rec = (union evrec *)&ev.data;
    104		rec->t.code = SEQ_SYNCTIMER;
    105		rec->t.time = time;
    106		q->sync_event_put = 1;
    107		snd_seq_kernel_client_enqueue(dp->cseq, &ev, NULL, true);
    108	}
    109
    110	wait_event_interruptible_timeout(q->sync_sleep, ! q->sync_event_put, HZ);
    111	if (signal_pending(current))
    112		/* interrupted - return 0 to finish sync */
    113		q->sync_event_put = 0;
    114	if (! q->sync_event_put || q->sync_time >= time)
    115		return 0;
    116	return 1;
    117}
    118
    119/*
    120 * wake up sync - echo event was catched
    121 */
    122void
    123snd_seq_oss_writeq_wakeup(struct seq_oss_writeq *q, abstime_t time)
    124{
    125	unsigned long flags;
    126
    127	spin_lock_irqsave(&q->sync_lock, flags);
    128	q->sync_time = time;
    129	q->sync_event_put = 0;
    130	wake_up(&q->sync_sleep);
    131	spin_unlock_irqrestore(&q->sync_lock, flags);
    132}
    133
    134
    135/*
    136 * return the unused pool size
    137 */
    138int
    139snd_seq_oss_writeq_get_free_size(struct seq_oss_writeq *q)
    140{
    141	struct snd_seq_client_pool pool;
    142	pool.client = q->dp->cseq;
    143	snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_GET_CLIENT_POOL, &pool);
    144	return pool.output_free;
    145}
    146
    147
    148/*
    149 * set output threshold size from ioctl
    150 */
    151void
    152snd_seq_oss_writeq_set_output(struct seq_oss_writeq *q, int val)
    153{
    154	struct snd_seq_client_pool pool;
    155	pool.client = q->dp->cseq;
    156	snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_GET_CLIENT_POOL, &pool);
    157	pool.output_room = val;
    158	snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_SET_CLIENT_POOL, &pool);
    159}
    160