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_rw.c (4586B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * OSS compatible sequencer driver
      4 *
      5 * read/write/select interface to device file
      6 *
      7 * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
      8 */
      9
     10#include "seq_oss_device.h"
     11#include "seq_oss_readq.h"
     12#include "seq_oss_writeq.h"
     13#include "seq_oss_synth.h"
     14#include <sound/seq_oss_legacy.h>
     15#include "seq_oss_event.h"
     16#include "seq_oss_timer.h"
     17#include "../seq_clientmgr.h"
     18
     19
     20/*
     21 * protoypes
     22 */
     23static int insert_queue(struct seq_oss_devinfo *dp, union evrec *rec, struct file *opt);
     24
     25
     26/*
     27 * read interface
     28 */
     29
     30int
     31snd_seq_oss_read(struct seq_oss_devinfo *dp, char __user *buf, int count)
     32{
     33	struct seq_oss_readq *readq = dp->readq;
     34	int result = 0, err = 0;
     35	int ev_len;
     36	union evrec rec;
     37	unsigned long flags;
     38
     39	if (readq == NULL || ! is_read_mode(dp->file_mode))
     40		return -ENXIO;
     41
     42	while (count >= SHORT_EVENT_SIZE) {
     43		snd_seq_oss_readq_lock(readq, flags);
     44		err = snd_seq_oss_readq_pick(readq, &rec);
     45		if (err == -EAGAIN &&
     46		    !is_nonblock_mode(dp->file_mode) && result == 0) {
     47			snd_seq_oss_readq_unlock(readq, flags);
     48			snd_seq_oss_readq_wait(readq);
     49			snd_seq_oss_readq_lock(readq, flags);
     50			if (signal_pending(current))
     51				err = -ERESTARTSYS;
     52			else
     53				err = snd_seq_oss_readq_pick(readq, &rec);
     54		}
     55		if (err < 0) {
     56			snd_seq_oss_readq_unlock(readq, flags);
     57			break;
     58		}
     59		ev_len = ev_length(&rec);
     60		if (ev_len < count) {
     61			snd_seq_oss_readq_unlock(readq, flags);
     62			break;
     63		}
     64		snd_seq_oss_readq_free(readq);
     65		snd_seq_oss_readq_unlock(readq, flags);
     66		if (copy_to_user(buf, &rec, ev_len)) {
     67			err = -EFAULT;
     68			break;
     69		}
     70		result += ev_len;
     71		buf += ev_len;
     72		count -= ev_len;
     73	}
     74	return result > 0 ? result : err;
     75}
     76
     77
     78/*
     79 * write interface
     80 */
     81
     82int
     83snd_seq_oss_write(struct seq_oss_devinfo *dp, const char __user *buf, int count, struct file *opt)
     84{
     85	int result = 0, err = 0;
     86	int ev_size, fmt;
     87	union evrec rec;
     88
     89	if (! is_write_mode(dp->file_mode) || dp->writeq == NULL)
     90		return -ENXIO;
     91
     92	while (count >= SHORT_EVENT_SIZE) {
     93		if (copy_from_user(&rec, buf, SHORT_EVENT_SIZE)) {
     94			err = -EFAULT;
     95			break;
     96		}
     97		if (rec.s.code == SEQ_FULLSIZE) {
     98			/* load patch */
     99			if (result > 0) {
    100				err = -EINVAL;
    101				break;
    102			}
    103			fmt = (*(unsigned short *)rec.c) & 0xffff;
    104			/* FIXME the return value isn't correct */
    105			return snd_seq_oss_synth_load_patch(dp, rec.s.dev,
    106							    fmt, buf, 0, count);
    107		}
    108		if (ev_is_long(&rec)) {
    109			/* extended code */
    110			if (rec.s.code == SEQ_EXTENDED &&
    111			    dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC) {
    112				err = -EINVAL;
    113				break;
    114			}
    115			ev_size = LONG_EVENT_SIZE;
    116			if (count < ev_size)
    117				break;
    118			/* copy the reset 4 bytes */
    119			if (copy_from_user(rec.c + SHORT_EVENT_SIZE,
    120					   buf + SHORT_EVENT_SIZE,
    121					   LONG_EVENT_SIZE - SHORT_EVENT_SIZE)) {
    122				err = -EFAULT;
    123				break;
    124			}
    125		} else {
    126			/* old-type code */
    127			if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC) {
    128				err = -EINVAL;
    129				break;
    130			}
    131			ev_size = SHORT_EVENT_SIZE;
    132		}
    133
    134		/* insert queue */
    135		err = insert_queue(dp, &rec, opt);
    136		if (err < 0)
    137			break;
    138
    139		result += ev_size;
    140		buf += ev_size;
    141		count -= ev_size;
    142	}
    143	return result > 0 ? result : err;
    144}
    145
    146
    147/*
    148 * insert event record to write queue
    149 * return: 0 = OK, non-zero = NG
    150 */
    151static int
    152insert_queue(struct seq_oss_devinfo *dp, union evrec *rec, struct file *opt)
    153{
    154	int rc = 0;
    155	struct snd_seq_event event;
    156
    157	/* if this is a timing event, process the current time */
    158	if (snd_seq_oss_process_timer_event(dp->timer, rec))
    159		return 0; /* no need to insert queue */
    160
    161	/* parse this event */
    162	memset(&event, 0, sizeof(event));
    163	/* set dummy -- to be sure */
    164	event.type = SNDRV_SEQ_EVENT_NOTEOFF;
    165	snd_seq_oss_fill_addr(dp, &event, dp->addr.client, dp->addr.port);
    166
    167	if (snd_seq_oss_process_event(dp, rec, &event))
    168		return 0; /* invalid event - no need to insert queue */
    169
    170	event.time.tick = snd_seq_oss_timer_cur_tick(dp->timer);
    171	if (dp->timer->realtime || !dp->timer->running)
    172		snd_seq_oss_dispatch(dp, &event, 0, 0);
    173	else
    174		rc = snd_seq_kernel_client_enqueue(dp->cseq, &event, opt,
    175						   !is_nonblock_mode(dp->file_mode));
    176	return rc;
    177}
    178		
    179
    180/*
    181 * select / poll
    182 */
    183  
    184__poll_t
    185snd_seq_oss_poll(struct seq_oss_devinfo *dp, struct file *file, poll_table * wait)
    186{
    187	__poll_t mask = 0;
    188
    189	/* input */
    190	if (dp->readq && is_read_mode(dp->file_mode)) {
    191		if (snd_seq_oss_readq_poll(dp->readq, file, wait))
    192			mask |= EPOLLIN | EPOLLRDNORM;
    193	}
    194
    195	/* output */
    196	if (dp->writeq && is_write_mode(dp->file_mode)) {
    197		if (snd_seq_kernel_client_write_poll(dp->cseq, file, wait))
    198			mask |= EPOLLOUT | EPOLLWRNORM;
    199	}
    200	return mask;
    201}