brintos

brintos / linux-shallow public Read only

0
0
Text · 4.5 KiB · 8a142fd Raw
202 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * OSS compatible sequencer driver4 *5 * read/write/select interface to device file6 *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 * protoypes22 */23static int insert_queue(struct seq_oss_devinfo *dp, union evrec *rec, struct file *opt);24 25 26/*27 * read interface28 */29 30int31snd_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			else53				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 interface80 */81 82int83snd_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 queue149 * return: 0 = OK, non-zero = NG150 */151static int152insert_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	else174		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 / poll182 */183  184__poll_t185snd_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}202