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 */ 23 static int insert_queue(struct seq_oss_devinfo *dp, union evrec *rec, struct file *opt); 24 25 26 /* 27 * read interface 28 */ 29 30 int 31 snd_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 (count < ev_len) { 61 err = -EINVAL; 62 snd_seq_oss_readq_unlock(readq, flags); 63 break; 64 } 65 snd_seq_oss_readq_free(readq); 66 snd_seq_oss_readq_unlock(readq, flags); 67 if (copy_to_user(buf, &rec, ev_len)) { 68 err = -EFAULT; 69 break; 70 } 71 result += ev_len; 72 buf += ev_len; 73 count -= ev_len; 74 } 75 return result > 0 ? result : err; 76 } 77 78 79 /* 80 * write interface 81 */ 82 83 int 84 snd_seq_oss_write(struct seq_oss_devinfo *dp, const char __user *buf, int count, struct file *opt) 85 { 86 int result = 0, err = 0; 87 int ev_size, fmt; 88 union evrec rec; 89 90 if (! is_write_mode(dp->file_mode) || dp->writeq == NULL) 91 return -ENXIO; 92 93 while (count >= SHORT_EVENT_SIZE) { 94 if (copy_from_user(&rec, buf, SHORT_EVENT_SIZE)) { 95 err = -EFAULT; 96 break; 97 } 98 if (rec.s.code == SEQ_FULLSIZE) { 99 /* load patch */ 100 if (result > 0) { 101 err = -EINVAL; 102 break; 103 } 104 fmt = (*(unsigned short *)rec.c) & 0xffff; 105 err = snd_seq_oss_synth_load_patch(dp, rec.s.dev, 106 fmt, buf, 0, count); 107 return err < 0 ? err : count; 108 } 109 if (ev_is_long(&rec)) { 110 /* extended code */ 111 if (rec.s.code == SEQ_EXTENDED && 112 dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC) { 113 err = -EINVAL; 114 break; 115 } 116 ev_size = LONG_EVENT_SIZE; 117 if (count < ev_size) 118 break; 119 /* copy the reset 4 bytes */ 120 if (copy_from_user(rec.c + SHORT_EVENT_SIZE, 121 buf + SHORT_EVENT_SIZE, 122 LONG_EVENT_SIZE - SHORT_EVENT_SIZE)) { 123 err = -EFAULT; 124 break; 125 } 126 } else { 127 /* old-type code */ 128 if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC) { 129 err = -EINVAL; 130 break; 131 } 132 ev_size = SHORT_EVENT_SIZE; 133 } 134 135 /* insert queue */ 136 err = insert_queue(dp, &rec, opt); 137 if (err < 0) 138 break; 139 140 result += ev_size; 141 buf += ev_size; 142 count -= ev_size; 143 } 144 return result > 0 ? result : err; 145 } 146 147 148 /* 149 * insert event record to write queue 150 * return: 0 = OK, non-zero = NG 151 */ 152 static int 153 insert_queue(struct seq_oss_devinfo *dp, union evrec *rec, struct file *opt) 154 { 155 int rc = 0; 156 struct snd_seq_event event; 157 158 /* if this is a timing event, process the current time */ 159 if (snd_seq_oss_process_timer_event(dp->timer, rec)) 160 return 0; /* no need to insert queue */ 161 162 /* parse this event */ 163 memset(&event, 0, sizeof(event)); 164 /* set dummy -- to be sure */ 165 event.type = SNDRV_SEQ_EVENT_NOTEOFF; 166 snd_seq_oss_fill_addr(dp, &event, dp->addr.client, dp->addr.port); 167 168 snd_use_lock_t *lock __free(seq_oss_use_lock) = NULL; 169 170 if (snd_seq_oss_process_event(dp, rec, &event, &lock)) 171 return 0; /* invalid event - no need to insert queue */ 172 173 event.time.tick = snd_seq_oss_timer_cur_tick(dp->timer); 174 if (dp->timer->realtime || !dp->timer->running) 175 snd_seq_oss_dispatch(dp, &event, 0, 0); 176 else 177 rc = snd_seq_kernel_client_enqueue(dp->cseq, &event, opt, 178 !is_nonblock_mode(dp->file_mode)); 179 return rc; 180 } 181 182 183 /* 184 * select / poll 185 */ 186 187 __poll_t 188 snd_seq_oss_poll(struct seq_oss_devinfo *dp, struct file *file, poll_table * wait) 189 { 190 __poll_t mask = 0; 191 192 /* input */ 193 if (dp->readq && is_read_mode(dp->file_mode)) { 194 if (snd_seq_oss_readq_poll(dp->readq, file, wait)) 195 mask |= EPOLLIN | EPOLLRDNORM; 196 } 197 198 /* output */ 199 if (dp->writeq && is_write_mode(dp->file_mode)) { 200 if (snd_seq_kernel_client_write_poll(dp->cseq, file, wait)) 201 mask |= EPOLLOUT | EPOLLWRNORM; 202 } 203 return mask; 204 } 205