rawmidi.c 49.1 KB
Newer Older
L
Linus Torvalds 已提交
1 2
/*
 *  Abstract layer for MIDI v1.0 stream
3
 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
L
Linus Torvalds 已提交
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 */

#include <sound/core.h>
#include <linux/major.h>
#include <linux/init.h>
25
#include <linux/sched/signal.h>
L
Linus Torvalds 已提交
26 27 28
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/wait.h>
29
#include <linux/mutex.h>
30
#include <linux/module.h>
L
Linus Torvalds 已提交
31
#include <linux/delay.h>
32
#include <linux/mm.h>
L
Linus Torvalds 已提交
33 34 35 36 37 38
#include <sound/rawmidi.h>
#include <sound/info.h>
#include <sound/control.h>
#include <sound/minors.h>
#include <sound/initval.h>

39
MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
L
Linus Torvalds 已提交
40 41 42 43
MODULE_DESCRIPTION("Midlevel RawMidi code for ALSA.");
MODULE_LICENSE("GPL");

#ifdef CONFIG_SND_OSSEMUL
44
static int midi_map[SNDRV_CARDS];
L
Linus Torvalds 已提交
45 46 47 48 49 50 51
static int amidi_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1};
module_param_array(midi_map, int, NULL, 0444);
MODULE_PARM_DESC(midi_map, "Raw MIDI device number assigned to 1st OSS device.");
module_param_array(amidi_map, int, NULL, 0444);
MODULE_PARM_DESC(amidi_map, "Raw MIDI device number assigned to 2nd OSS device.");
#endif /* CONFIG_SND_OSSEMUL */

52 53 54 55
static int snd_rawmidi_free(struct snd_rawmidi *rawmidi);
static int snd_rawmidi_dev_free(struct snd_device *device);
static int snd_rawmidi_dev_register(struct snd_device *device);
static int snd_rawmidi_dev_disconnect(struct snd_device *device);
L
Linus Torvalds 已提交
56

57
static LIST_HEAD(snd_rawmidi_devices);
58
static DEFINE_MUTEX(register_mutex);
L
Linus Torvalds 已提交
59

60
#define rmidi_err(rmidi, fmt, args...) \
61
	dev_err(&(rmidi)->dev, fmt, ##args)
62
#define rmidi_warn(rmidi, fmt, args...) \
63
	dev_warn(&(rmidi)->dev, fmt, ##args)
64
#define rmidi_dbg(rmidi, fmt, args...) \
65
	dev_dbg(&(rmidi)->dev, fmt, ##args)
66

67 68 69 70
static struct snd_rawmidi *snd_rawmidi_search(struct snd_card *card, int device)
{
	struct snd_rawmidi *rawmidi;

71
	list_for_each_entry(rawmidi, &snd_rawmidi_devices, list)
72 73 74 75 76
		if (rawmidi->card == card && rawmidi->device == device)
			return rawmidi;
	return NULL;
}

L
Linus Torvalds 已提交
77 78 79 80 81 82 83 84 85 86 87 88
static inline unsigned short snd_rawmidi_file_flags(struct file *file)
{
	switch (file->f_mode & (FMODE_READ | FMODE_WRITE)) {
	case FMODE_WRITE:
		return SNDRV_RAWMIDI_LFLG_OUTPUT;
	case FMODE_READ:
		return SNDRV_RAWMIDI_LFLG_INPUT;
	default:
		return SNDRV_RAWMIDI_LFLG_OPEN;
	}
}

89
static inline int snd_rawmidi_ready(struct snd_rawmidi_substream *substream)
L
Linus Torvalds 已提交
90
{
91
	struct snd_rawmidi_runtime *runtime = substream->runtime;
92

L
Linus Torvalds 已提交
93 94 95
	return runtime->avail >= runtime->avail_min;
}

96 97
static inline int snd_rawmidi_ready_append(struct snd_rawmidi_substream *substream,
					   size_t count)
L
Linus Torvalds 已提交
98
{
99
	struct snd_rawmidi_runtime *runtime = substream->runtime;
100

L
Linus Torvalds 已提交
101 102 103 104
	return runtime->avail >= runtime->avail_min &&
	       (!substream->append || runtime->avail >= count);
}

105
static void snd_rawmidi_input_event_work(struct work_struct *work)
L
Linus Torvalds 已提交
106
{
107 108
	struct snd_rawmidi_runtime *runtime =
		container_of(work, struct snd_rawmidi_runtime, event_work);
109

110 111
	if (runtime->event)
		runtime->event(runtime->substream);
L
Linus Torvalds 已提交
112 113
}

114
static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream)
L
Linus Torvalds 已提交
115
{
116
	struct snd_rawmidi_runtime *runtime;
L
Linus Torvalds 已提交
117

118 119
	runtime = kzalloc(sizeof(*runtime), GFP_KERNEL);
	if (!runtime)
L
Linus Torvalds 已提交
120
		return -ENOMEM;
121
	runtime->substream = substream;
L
Linus Torvalds 已提交
122 123
	spin_lock_init(&runtime->lock);
	init_waitqueue_head(&runtime->sleep);
124
	INIT_WORK(&runtime->event_work, snd_rawmidi_input_event_work);
L
Linus Torvalds 已提交
125 126 127 128 129 130 131
	runtime->event = NULL;
	runtime->buffer_size = PAGE_SIZE;
	runtime->avail_min = 1;
	if (substream->stream == SNDRV_RAWMIDI_STREAM_INPUT)
		runtime->avail = 0;
	else
		runtime->avail = runtime->buffer_size;
132
	runtime->buffer = kvzalloc(runtime->buffer_size, GFP_KERNEL);
133
	if (!runtime->buffer) {
L
Linus Torvalds 已提交
134 135 136 137 138 139 140 141
		kfree(runtime);
		return -ENOMEM;
	}
	runtime->appl_ptr = runtime->hw_ptr = 0;
	substream->runtime = runtime;
	return 0;
}

142
static int snd_rawmidi_runtime_free(struct snd_rawmidi_substream *substream)
L
Linus Torvalds 已提交
143
{
144
	struct snd_rawmidi_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
145

146
	kvfree(runtime->buffer);
L
Linus Torvalds 已提交
147 148 149 150 151
	kfree(runtime);
	substream->runtime = NULL;
	return 0;
}

152
static inline void snd_rawmidi_output_trigger(struct snd_rawmidi_substream *substream, int up)
L
Linus Torvalds 已提交
153
{
154 155
	if (!substream->opened)
		return;
156
	substream->ops->trigger(substream, up);
L
Linus Torvalds 已提交
157 158
}

159
static void snd_rawmidi_input_trigger(struct snd_rawmidi_substream *substream, int up)
L
Linus Torvalds 已提交
160
{
161 162
	if (!substream->opened)
		return;
L
Linus Torvalds 已提交
163
	substream->ops->trigger(substream, up);
164 165
	if (!up)
		cancel_work_sync(&substream->runtime->event_work);
L
Linus Torvalds 已提交
166 167
}

168 169 170 171 172 173 174 175 176 177
static void __reset_runtime_ptrs(struct snd_rawmidi_runtime *runtime,
				 bool is_input)
{
	runtime->drain = 0;
	runtime->appl_ptr = runtime->hw_ptr = 0;
	runtime->avail = is_input ? 0 : runtime->buffer_size;
}

static void reset_runtime_ptrs(struct snd_rawmidi_runtime *runtime,
			       bool is_input)
L
Linus Torvalds 已提交
178 179 180 181
{
	unsigned long flags;

	spin_lock_irqsave(&runtime->lock, flags);
182
	__reset_runtime_ptrs(runtime, is_input);
L
Linus Torvalds 已提交
183
	spin_unlock_irqrestore(&runtime->lock, flags);
184 185 186 187 188 189
}

int snd_rawmidi_drop_output(struct snd_rawmidi_substream *substream)
{
	snd_rawmidi_output_trigger(substream, 0);
	reset_runtime_ptrs(substream->runtime, false);
L
Linus Torvalds 已提交
190 191
	return 0;
}
192
EXPORT_SYMBOL(snd_rawmidi_drop_output);
L
Linus Torvalds 已提交
193

194
int snd_rawmidi_drain_output(struct snd_rawmidi_substream *substream)
L
Linus Torvalds 已提交
195 196 197
{
	int err;
	long timeout;
198
	struct snd_rawmidi_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
199 200 201 202 203 204 205 206 207

	err = 0;
	runtime->drain = 1;
	timeout = wait_event_interruptible_timeout(runtime->sleep,
				(runtime->avail >= runtime->buffer_size),
				10*HZ);
	if (signal_pending(current))
		err = -ERESTARTSYS;
	if (runtime->avail < runtime->buffer_size && !timeout) {
208 209 210
		rmidi_warn(substream->rmidi,
			   "rawmidi drain error (avail = %li, buffer_size = %li)\n",
			   (long)runtime->avail, (long)runtime->buffer_size);
L
Linus Torvalds 已提交
211 212 213 214 215 216 217 218 219 220 221 222 223
		err = -EIO;
	}
	runtime->drain = 0;
	if (err != -ERESTARTSYS) {
		/* we need wait a while to make sure that Tx FIFOs are empty */
		if (substream->ops->drain)
			substream->ops->drain(substream);
		else
			msleep(50);
		snd_rawmidi_drop_output(substream);
	}
	return err;
}
224
EXPORT_SYMBOL(snd_rawmidi_drain_output);
L
Linus Torvalds 已提交
225

226
int snd_rawmidi_drain_input(struct snd_rawmidi_substream *substream)
L
Linus Torvalds 已提交
227 228
{
	snd_rawmidi_input_trigger(substream, 0);
229
	reset_runtime_ptrs(substream->runtime, true);
L
Linus Torvalds 已提交
230 231
	return 0;
}
232
EXPORT_SYMBOL(snd_rawmidi_drain_input);
L
Linus Torvalds 已提交
233

234 235 236 237 238 239
/* look for an available substream for the given stream direction;
 * if a specific subdevice is given, try to assign it
 */
static int assign_substream(struct snd_rawmidi *rmidi, int subdevice,
			    int stream, int mode,
			    struct snd_rawmidi_substream **sub_ret)
L
Linus Torvalds 已提交
240
{
241 242 243 244 245 246
	struct snd_rawmidi_substream *substream;
	struct snd_rawmidi_str *s = &rmidi->streams[stream];
	static unsigned int info_flags[2] = {
		[SNDRV_RAWMIDI_STREAM_OUTPUT] = SNDRV_RAWMIDI_INFO_OUTPUT,
		[SNDRV_RAWMIDI_STREAM_INPUT] = SNDRV_RAWMIDI_INFO_INPUT,
	};
L
Linus Torvalds 已提交
247

248
	if (!(rmidi->info_flags & info_flags[stream]))
249
		return -ENXIO;
250 251 252 253 254 255
	if (subdevice >= 0 && subdevice >= s->substream_count)
		return -ENODEV;

	list_for_each_entry(substream, &s->substreams, list) {
		if (substream->opened) {
			if (stream == SNDRV_RAWMIDI_STREAM_INPUT ||
256 257
			    !(mode & SNDRV_RAWMIDI_LFLG_APPEND) ||
			    !substream->append)
258 259 260 261 262 263
				continue;
		}
		if (subdevice < 0 || subdevice == substream->number) {
			*sub_ret = substream;
			return 0;
		}
L
Linus Torvalds 已提交
264
	}
265 266
	return -EAGAIN;
}
267

268 269 270 271 272 273 274
/* open and do ref-counting for the given substream */
static int open_substream(struct snd_rawmidi *rmidi,
			  struct snd_rawmidi_substream *substream,
			  int mode)
{
	int err;

275 276 277 278 279
	if (substream->use_count == 0) {
		err = snd_rawmidi_runtime_create(substream);
		if (err < 0)
			return err;
		err = substream->ops->open(substream);
280 281
		if (err < 0) {
			snd_rawmidi_runtime_free(substream);
282
			return err;
283
		}
284
		substream->opened = 1;
285
		substream->active_sensing = 0;
286 287
		if (mode & SNDRV_RAWMIDI_LFLG_APPEND)
			substream->append = 1;
288
		substream->pid = get_pid(task_pid(current));
289
		rmidi->streams[substream->stream].substream_opened++;
290 291
	}
	substream->use_count++;
292 293 294 295 296 297 298 299 300 301 302 303 304 305
	return 0;
}

static void close_substream(struct snd_rawmidi *rmidi,
			    struct snd_rawmidi_substream *substream,
			    int cleanup);

static int rawmidi_open_priv(struct snd_rawmidi *rmidi, int subdevice, int mode,
			     struct snd_rawmidi_file *rfile)
{
	struct snd_rawmidi_substream *sinput = NULL, *soutput = NULL;
	int err;

	rfile->input = rfile->output = NULL;
L
Linus Torvalds 已提交
306
	if (mode & SNDRV_RAWMIDI_LFLG_INPUT) {
307 308 309 310
		err = assign_substream(rmidi, subdevice,
				       SNDRV_RAWMIDI_STREAM_INPUT,
				       mode, &sinput);
		if (err < 0)
311
			return err;
L
Linus Torvalds 已提交
312 313
	}
	if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) {
314 315 316 317
		err = assign_substream(rmidi, subdevice,
				       SNDRV_RAWMIDI_STREAM_OUTPUT,
				       mode, &soutput);
		if (err < 0)
318
			return err;
L
Linus Torvalds 已提交
319
	}
320 321 322 323

	if (sinput) {
		err = open_substream(rmidi, sinput, mode);
		if (err < 0)
324
			return err;
L
Linus Torvalds 已提交
325
	}
326 327 328 329 330
	if (soutput) {
		err = open_substream(rmidi, soutput, mode);
		if (err < 0) {
			if (sinput)
				close_substream(rmidi, sinput, 0);
331
			return err;
L
Linus Torvalds 已提交
332 333
		}
	}
334 335 336 337

	rfile->rmidi = rmidi;
	rfile->input = sinput;
	rfile->output = soutput;
L
Linus Torvalds 已提交
338
	return 0;
339 340 341 342
}

/* called from sound/core/seq/seq_midi.c */
int snd_rawmidi_kernel_open(struct snd_card *card, int device, int subdevice,
343
			    int mode, struct snd_rawmidi_file *rfile)
344 345
{
	struct snd_rawmidi *rmidi;
346
	int err = 0;
347 348 349 350 351 352

	if (snd_BUG_ON(!rfile))
		return -EINVAL;

	mutex_lock(&register_mutex);
	rmidi = snd_rawmidi_search(card, device);
353 354 355 356
	if (!rmidi)
		err = -ENODEV;
	else if (!try_module_get(rmidi->card->module))
		err = -ENXIO;
357
	mutex_unlock(&register_mutex);
358 359
	if (err < 0)
		return err;
360 361 362 363 364 365

	mutex_lock(&rmidi->open_mutex);
	err = rawmidi_open_priv(rmidi, subdevice, mode, rfile);
	mutex_unlock(&rmidi->open_mutex);
	if (err < 0)
		module_put(rmidi->card->module);
L
Linus Torvalds 已提交
366 367
	return err;
}
368
EXPORT_SYMBOL(snd_rawmidi_kernel_open);
L
Linus Torvalds 已提交
369 370 371 372

static int snd_rawmidi_open(struct inode *inode, struct file *file)
{
	int maj = imajor(inode);
373
	struct snd_card *card;
374
	int subdevice;
L
Linus Torvalds 已提交
375 376
	unsigned short fflags;
	int err;
377
	struct snd_rawmidi *rmidi;
378
	struct snd_rawmidi_file *rawmidi_file = NULL;
379
	wait_queue_entry_t wait;
L
Linus Torvalds 已提交
380

381
	if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK))
382 383
		return -EINVAL;		/* invalid combination */

T
Takashi Iwai 已提交
384 385 386 387
	err = nonseekable_open(inode, file);
	if (err < 0)
		return err;

388
	if (maj == snd_major) {
389 390
		rmidi = snd_lookup_minor_data(iminor(inode),
					      SNDRV_DEVICE_TYPE_RAWMIDI);
L
Linus Torvalds 已提交
391
#ifdef CONFIG_SND_OSSEMUL
392
	} else if (maj == SOUND_MAJOR) {
393 394
		rmidi = snd_lookup_oss_minor_data(iminor(inode),
						  SNDRV_OSS_DEVICE_TYPE_MIDI);
L
Linus Torvalds 已提交
395
#endif
396
	} else
L
Linus Torvalds 已提交
397 398 399 400
		return -ENXIO;

	if (rmidi == NULL)
		return -ENODEV;
401

402 403
	if (!try_module_get(rmidi->card->module)) {
		snd_card_unref(rmidi->card);
404
		return -ENXIO;
405
	}
406 407

	mutex_lock(&rmidi->open_mutex);
L
Linus Torvalds 已提交
408 409 410
	card = rmidi->card;
	err = snd_card_file_add(card, file);
	if (err < 0)
411
		goto __error_card;
L
Linus Torvalds 已提交
412
	fflags = snd_rawmidi_file_flags(file);
413
	if ((file->f_flags & O_APPEND) || maj == SOUND_MAJOR) /* OSS emul? */
L
Linus Torvalds 已提交
414 415 416
		fflags |= SNDRV_RAWMIDI_LFLG_APPEND;
	rawmidi_file = kmalloc(sizeof(*rawmidi_file), GFP_KERNEL);
	if (rawmidi_file == NULL) {
417 418
		err = -ENOMEM;
		goto __error;
L
Linus Torvalds 已提交
419 420 421 422
	}
	init_waitqueue_entry(&wait, current);
	add_wait_queue(&rmidi->open_wait, &wait);
	while (1) {
423
		subdevice = snd_ctl_get_preferred_subdevice(card, SND_CTL_SUBDEV_RAWMIDI);
424
		err = rawmidi_open_priv(rmidi, subdevice, fflags, rawmidi_file);
L
Linus Torvalds 已提交
425 426 427 428 429 430 431 432 433 434
		if (err >= 0)
			break;
		if (err == -EAGAIN) {
			if (file->f_flags & O_NONBLOCK) {
				err = -EBUSY;
				break;
			}
		} else
			break;
		set_current_state(TASK_INTERRUPTIBLE);
435
		mutex_unlock(&rmidi->open_mutex);
L
Linus Torvalds 已提交
436
		schedule();
437
		mutex_lock(&rmidi->open_mutex);
438 439 440 441
		if (rmidi->card->shutdown) {
			err = -ENODEV;
			break;
		}
L
Linus Torvalds 已提交
442 443 444 445 446
		if (signal_pending(current)) {
			err = -ERESTARTSYS;
			break;
		}
	}
447 448 449 450 451
	remove_wait_queue(&rmidi->open_wait, &wait);
	if (err < 0) {
		kfree(rawmidi_file);
		goto __error;
	}
L
Linus Torvalds 已提交
452 453 454 455 456 457
#ifdef CONFIG_SND_OSSEMUL
	if (rawmidi_file->input && rawmidi_file->input->runtime)
		rawmidi_file->input->runtime->oss = (maj == SOUND_MAJOR);
	if (rawmidi_file->output && rawmidi_file->output->runtime)
		rawmidi_file->output->runtime->oss = (maj == SOUND_MAJOR);
#endif
458 459
	file->private_data = rawmidi_file;
	mutex_unlock(&rmidi->open_mutex);
460
	snd_card_unref(rmidi->card);
461 462 463 464 465
	return 0;

 __error:
	snd_card_file_remove(card, file);
 __error_card:
466
	mutex_unlock(&rmidi->open_mutex);
467
	module_put(rmidi->card->module);
468
	snd_card_unref(rmidi->card);
L
Linus Torvalds 已提交
469 470 471
	return err;
}

472 473 474
static void close_substream(struct snd_rawmidi *rmidi,
			    struct snd_rawmidi_substream *substream,
			    int cleanup)
L
Linus Torvalds 已提交
475
{
476 477
	if (--substream->use_count)
		return;
L
Linus Torvalds 已提交
478

479 480 481 482
	if (cleanup) {
		if (substream->stream == SNDRV_RAWMIDI_STREAM_INPUT)
			snd_rawmidi_input_trigger(substream, 0);
		else {
L
Linus Torvalds 已提交
483 484
			if (substream->active_sensing) {
				unsigned char buf = 0xfe;
485 486 487
				/* sending single active sensing message
				 * to shut the device up
				 */
L
Linus Torvalds 已提交
488 489 490 491 492 493
				snd_rawmidi_kernel_write(substream, &buf, 1);
			}
			if (snd_rawmidi_drain_output(substream) == -ERESTARTSYS)
				snd_rawmidi_output_trigger(substream, 0);
		}
	}
494 495 496 497 498 499
	substream->ops->close(substream);
	if (substream->runtime->private_free)
		substream->runtime->private_free(substream);
	snd_rawmidi_runtime_free(substream);
	substream->opened = 0;
	substream->append = 0;
500 501
	put_pid(substream->pid);
	substream->pid = NULL;
502
	rmidi->streams[substream->stream].substream_opened--;
503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519
}

static void rawmidi_release_priv(struct snd_rawmidi_file *rfile)
{
	struct snd_rawmidi *rmidi;

	rmidi = rfile->rmidi;
	mutex_lock(&rmidi->open_mutex);
	if (rfile->input) {
		close_substream(rmidi, rfile->input, 1);
		rfile->input = NULL;
	}
	if (rfile->output) {
		close_substream(rmidi, rfile->output, 1);
		rfile->output = NULL;
	}
	rfile->rmidi = NULL;
520
	mutex_unlock(&rmidi->open_mutex);
521 522 523 524 525 526 527 528 529 530
	wake_up(&rmidi->open_wait);
}

/* called from sound/core/seq/seq_midi.c */
int snd_rawmidi_kernel_release(struct snd_rawmidi_file *rfile)
{
	struct snd_rawmidi *rmidi;

	if (snd_BUG_ON(!rfile))
		return -ENXIO;
531

532 533
	rmidi = rfile->rmidi;
	rawmidi_release_priv(rfile);
L
Linus Torvalds 已提交
534 535 536
	module_put(rmidi->card->module);
	return 0;
}
537
EXPORT_SYMBOL(snd_rawmidi_kernel_release);
L
Linus Torvalds 已提交
538 539 540

static int snd_rawmidi_release(struct inode *inode, struct file *file)
{
541 542
	struct snd_rawmidi_file *rfile;
	struct snd_rawmidi *rmidi;
543
	struct module *module;
L
Linus Torvalds 已提交
544 545 546

	rfile = file->private_data;
	rmidi = rfile->rmidi;
547
	rawmidi_release_priv(rfile);
L
Linus Torvalds 已提交
548
	kfree(rfile);
549
	module = rmidi->card->module;
L
Linus Torvalds 已提交
550
	snd_card_file_remove(rmidi->card, file);
551
	module_put(module);
552
	return 0;
L
Linus Torvalds 已提交
553 554
}

A
Adrian Bunk 已提交
555 556
static int snd_rawmidi_info(struct snd_rawmidi_substream *substream,
			    struct snd_rawmidi_info *info)
L
Linus Torvalds 已提交
557
{
558
	struct snd_rawmidi *rmidi;
559

L
Linus Torvalds 已提交
560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577
	if (substream == NULL)
		return -ENODEV;
	rmidi = substream->rmidi;
	memset(info, 0, sizeof(*info));
	info->card = rmidi->card->number;
	info->device = rmidi->device;
	info->subdevice = substream->number;
	info->stream = substream->stream;
	info->flags = rmidi->info_flags;
	strcpy(info->id, rmidi->id);
	strcpy(info->name, rmidi->name);
	strcpy(info->subname, substream->name);
	info->subdevices_count = substream->pstr->substream_count;
	info->subdevices_avail = (substream->pstr->substream_count -
				  substream->pstr->substream_opened);
	return 0;
}

578
static int snd_rawmidi_info_user(struct snd_rawmidi_substream *substream,
579
				 struct snd_rawmidi_info __user *_info)
L
Linus Torvalds 已提交
580
{
581
	struct snd_rawmidi_info info;
L
Linus Torvalds 已提交
582
	int err;
583 584 585

	err = snd_rawmidi_info(substream, &info);
	if (err < 0)
L
Linus Torvalds 已提交
586
		return err;
587
	if (copy_to_user(_info, &info, sizeof(struct snd_rawmidi_info)))
L
Linus Torvalds 已提交
588 589 590 591
		return -EFAULT;
	return 0;
}

592 593
static int __snd_rawmidi_info_select(struct snd_card *card,
				     struct snd_rawmidi_info *info)
L
Linus Torvalds 已提交
594
{
595 596 597
	struct snd_rawmidi *rmidi;
	struct snd_rawmidi_str *pstr;
	struct snd_rawmidi_substream *substream;
598 599

	rmidi = snd_rawmidi_search(card, info->device);
600 601
	if (!rmidi)
		return -ENXIO;
L
Linus Torvalds 已提交
602 603 604 605 606 607 608
	if (info->stream < 0 || info->stream > 1)
		return -EINVAL;
	pstr = &rmidi->streams[info->stream];
	if (pstr->substream_count == 0)
		return -ENOENT;
	if (info->subdevice >= pstr->substream_count)
		return -ENXIO;
609
	list_for_each_entry(substream, &pstr->substreams, list) {
L
Linus Torvalds 已提交
610 611 612 613 614
		if ((unsigned int)substream->number == info->subdevice)
			return snd_rawmidi_info(substream, info);
	}
	return -ENXIO;
}
615 616 617 618 619 620 621 622 623 624

int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info)
{
	int ret;

	mutex_lock(&register_mutex);
	ret = __snd_rawmidi_info_select(card, info);
	mutex_unlock(&register_mutex);
	return ret;
}
625
EXPORT_SYMBOL(snd_rawmidi_info_select);
L
Linus Torvalds 已提交
626

627 628
static int snd_rawmidi_info_select_user(struct snd_card *card,
					struct snd_rawmidi_info __user *_info)
L
Linus Torvalds 已提交
629 630
{
	int err;
631
	struct snd_rawmidi_info info;
632

L
Linus Torvalds 已提交
633 634 635 636 637 638
	if (get_user(info.device, &_info->device))
		return -EFAULT;
	if (get_user(info.stream, &_info->stream))
		return -EFAULT;
	if (get_user(info.subdevice, &_info->subdevice))
		return -EFAULT;
639 640
	err = snd_rawmidi_info_select(card, &info);
	if (err < 0)
L
Linus Torvalds 已提交
641
		return err;
642
	if (copy_to_user(_info, &info, sizeof(struct snd_rawmidi_info)))
L
Linus Torvalds 已提交
643 644 645 646
		return -EFAULT;
	return 0;
}

647 648 649
static int resize_runtime_buffer(struct snd_rawmidi_runtime *runtime,
				 struct snd_rawmidi_params *params,
				 bool is_input)
L
Linus Torvalds 已提交
650
{
651
	char *newbuf, *oldbuf;
652 653

	if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L)
L
Linus Torvalds 已提交
654
		return -EINVAL;
655
	if (params->avail_min < 1 || params->avail_min > params->buffer_size)
L
Linus Torvalds 已提交
656 657
		return -EINVAL;
	if (params->buffer_size != runtime->buffer_size) {
658
		newbuf = kvzalloc(params->buffer_size, GFP_KERNEL);
659
		if (!newbuf)
L
Linus Torvalds 已提交
660
			return -ENOMEM;
661 662
		spin_lock_irq(&runtime->lock);
		oldbuf = runtime->buffer;
L
Linus Torvalds 已提交
663 664
		runtime->buffer = newbuf;
		runtime->buffer_size = params->buffer_size;
665
		__reset_runtime_ptrs(runtime, is_input);
666
		spin_unlock_irq(&runtime->lock);
667
		kvfree(oldbuf);
L
Linus Torvalds 已提交
668 669 670 671
	}
	runtime->avail_min = params->avail_min;
	return 0;
}
672 673 674 675 676 677 678 679 680 681

int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream,
			      struct snd_rawmidi_params *params)
{
	if (substream->append && substream->use_count > 1)
		return -EBUSY;
	snd_rawmidi_drain_output(substream);
	substream->active_sensing = !params->no_active_sensing;
	return resize_runtime_buffer(substream->runtime, params, false);
}
682
EXPORT_SYMBOL(snd_rawmidi_output_params);
L
Linus Torvalds 已提交
683

684
int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream,
685
			     struct snd_rawmidi_params *params)
L
Linus Torvalds 已提交
686 687
{
	snd_rawmidi_drain_input(substream);
688
	return resize_runtime_buffer(substream->runtime, params, true);
L
Linus Torvalds 已提交
689
}
690
EXPORT_SYMBOL(snd_rawmidi_input_params);
L
Linus Torvalds 已提交
691

692
static int snd_rawmidi_output_status(struct snd_rawmidi_substream *substream,
693
				     struct snd_rawmidi_status *status)
L
Linus Torvalds 已提交
694
{
695
	struct snd_rawmidi_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
696 697 698 699 700 701 702 703 704

	memset(status, 0, sizeof(*status));
	status->stream = SNDRV_RAWMIDI_STREAM_OUTPUT;
	spin_lock_irq(&runtime->lock);
	status->avail = runtime->avail;
	spin_unlock_irq(&runtime->lock);
	return 0;
}

705
static int snd_rawmidi_input_status(struct snd_rawmidi_substream *substream,
706
				    struct snd_rawmidi_status *status)
L
Linus Torvalds 已提交
707
{
708
	struct snd_rawmidi_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
709 710 711 712 713 714 715 716 717 718 719 720 721

	memset(status, 0, sizeof(*status));
	status->stream = SNDRV_RAWMIDI_STREAM_INPUT;
	spin_lock_irq(&runtime->lock);
	status->avail = runtime->avail;
	status->xruns = runtime->xruns;
	runtime->xruns = 0;
	spin_unlock_irq(&runtime->lock);
	return 0;
}

static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
722
	struct snd_rawmidi_file *rfile;
L
Linus Torvalds 已提交
723 724 725 726 727 728 729 730 731 732
	void __user *argp = (void __user *)arg;

	rfile = file->private_data;
	if (((cmd >> 8) & 0xff) != 'W')
		return -ENOTTY;
	switch (cmd) {
	case SNDRV_RAWMIDI_IOCTL_PVERSION:
		return put_user(SNDRV_RAWMIDI_VERSION, (int __user *)argp) ? -EFAULT : 0;
	case SNDRV_RAWMIDI_IOCTL_INFO:
	{
733 734
		int stream;
		struct snd_rawmidi_info __user *info = argp;
735

L
Linus Torvalds 已提交
736 737 738 739 740 741 742 743 744 745 746 747 748
		if (get_user(stream, &info->stream))
			return -EFAULT;
		switch (stream) {
		case SNDRV_RAWMIDI_STREAM_INPUT:
			return snd_rawmidi_info_user(rfile->input, info);
		case SNDRV_RAWMIDI_STREAM_OUTPUT:
			return snd_rawmidi_info_user(rfile->output, info);
		default:
			return -EINVAL;
		}
	}
	case SNDRV_RAWMIDI_IOCTL_PARAMS:
	{
749
		struct snd_rawmidi_params params;
750

751
		if (copy_from_user(&params, argp, sizeof(struct snd_rawmidi_params)))
L
Linus Torvalds 已提交
752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768
			return -EFAULT;
		switch (params.stream) {
		case SNDRV_RAWMIDI_STREAM_OUTPUT:
			if (rfile->output == NULL)
				return -EINVAL;
			return snd_rawmidi_output_params(rfile->output, &params);
		case SNDRV_RAWMIDI_STREAM_INPUT:
			if (rfile->input == NULL)
				return -EINVAL;
			return snd_rawmidi_input_params(rfile->input, &params);
		default:
			return -EINVAL;
		}
	}
	case SNDRV_RAWMIDI_IOCTL_STATUS:
	{
		int err = 0;
769
		struct snd_rawmidi_status status;
770

771
		if (copy_from_user(&status, argp, sizeof(struct snd_rawmidi_status)))
L
Linus Torvalds 已提交
772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788
			return -EFAULT;
		switch (status.stream) {
		case SNDRV_RAWMIDI_STREAM_OUTPUT:
			if (rfile->output == NULL)
				return -EINVAL;
			err = snd_rawmidi_output_status(rfile->output, &status);
			break;
		case SNDRV_RAWMIDI_STREAM_INPUT:
			if (rfile->input == NULL)
				return -EINVAL;
			err = snd_rawmidi_input_status(rfile->input, &status);
			break;
		default:
			return -EINVAL;
		}
		if (err < 0)
			return err;
789
		if (copy_to_user(argp, &status, sizeof(struct snd_rawmidi_status)))
L
Linus Torvalds 已提交
790 791 792 793 794 795
			return -EFAULT;
		return 0;
	}
	case SNDRV_RAWMIDI_IOCTL_DROP:
	{
		int val;
796

L
Linus Torvalds 已提交
797 798 799 800 801 802 803 804 805 806 807 808 809 810
		if (get_user(val, (int __user *) argp))
			return -EFAULT;
		switch (val) {
		case SNDRV_RAWMIDI_STREAM_OUTPUT:
			if (rfile->output == NULL)
				return -EINVAL;
			return snd_rawmidi_drop_output(rfile->output);
		default:
			return -EINVAL;
		}
	}
	case SNDRV_RAWMIDI_IOCTL_DRAIN:
	{
		int val;
811

L
Linus Torvalds 已提交
812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827
		if (get_user(val, (int __user *) argp))
			return -EFAULT;
		switch (val) {
		case SNDRV_RAWMIDI_STREAM_OUTPUT:
			if (rfile->output == NULL)
				return -EINVAL;
			return snd_rawmidi_drain_output(rfile->output);
		case SNDRV_RAWMIDI_STREAM_INPUT:
			if (rfile->input == NULL)
				return -EINVAL;
			return snd_rawmidi_drain_input(rfile->input);
		default:
			return -EINVAL;
		}
	}
	default:
828 829
		rmidi_dbg(rfile->rmidi,
			  "rawmidi: unknown command = 0x%x\n", cmd);
L
Linus Torvalds 已提交
830 831 832 833
	}
	return -ENOTTY;
}

834 835
static int snd_rawmidi_control_ioctl(struct snd_card *card,
				     struct snd_ctl_file *control,
L
Linus Torvalds 已提交
836 837 838 839 840 841 842 843 844
				     unsigned int cmd,
				     unsigned long arg)
{
	void __user *argp = (void __user *)arg;

	switch (cmd) {
	case SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE:
	{
		int device;
845

L
Linus Torvalds 已提交
846 847
		if (get_user(device, (int __user *)argp))
			return -EFAULT;
848 849
		if (device >= SNDRV_RAWMIDI_DEVICES) /* next device is -1 */
			device = SNDRV_RAWMIDI_DEVICES - 1;
850
		mutex_lock(&register_mutex);
L
Linus Torvalds 已提交
851 852
		device = device < 0 ? 0 : device + 1;
		while (device < SNDRV_RAWMIDI_DEVICES) {
853
			if (snd_rawmidi_search(card, device))
L
Linus Torvalds 已提交
854 855 856 857 858
				break;
			device++;
		}
		if (device == SNDRV_RAWMIDI_DEVICES)
			device = -1;
859
		mutex_unlock(&register_mutex);
L
Linus Torvalds 已提交
860 861 862 863 864 865 866
		if (put_user(device, (int __user *)argp))
			return -EFAULT;
		return 0;
	}
	case SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE:
	{
		int val;
867

L
Linus Torvalds 已提交
868 869
		if (get_user(val, (int __user *)argp))
			return -EFAULT;
870
		control->preferred_subdevice[SND_CTL_SUBDEV_RAWMIDI] = val;
L
Linus Torvalds 已提交
871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886
		return 0;
	}
	case SNDRV_CTL_IOCTL_RAWMIDI_INFO:
		return snd_rawmidi_info_select_user(card, argp);
	}
	return -ENOIOCTLCMD;
}

/**
 * snd_rawmidi_receive - receive the input data from the device
 * @substream: the rawmidi substream
 * @buffer: the buffer pointer
 * @count: the data size to read
 *
 * Reads the data from the internal buffer.
 *
887
 * Return: The size of read data, or a negative error code on failure.
L
Linus Torvalds 已提交
888
 */
889 890
int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
			const unsigned char *buffer, int count)
L
Linus Torvalds 已提交
891 892 893
{
	unsigned long flags;
	int result = 0, count1;
894
	struct snd_rawmidi_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
895

896 897
	if (!substream->opened)
		return -EBADFD;
L
Linus Torvalds 已提交
898
	if (runtime->buffer == NULL) {
899 900
		rmidi_dbg(substream->rmidi,
			  "snd_rawmidi_receive: input is not active!!!\n");
L
Linus Torvalds 已提交
901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943
		return -EINVAL;
	}
	spin_lock_irqsave(&runtime->lock, flags);
	if (count == 1) {	/* special case, faster code */
		substream->bytes++;
		if (runtime->avail < runtime->buffer_size) {
			runtime->buffer[runtime->hw_ptr++] = buffer[0];
			runtime->hw_ptr %= runtime->buffer_size;
			runtime->avail++;
			result++;
		} else {
			runtime->xruns++;
		}
	} else {
		substream->bytes += count;
		count1 = runtime->buffer_size - runtime->hw_ptr;
		if (count1 > count)
			count1 = count;
		if (count1 > (int)(runtime->buffer_size - runtime->avail))
			count1 = runtime->buffer_size - runtime->avail;
		memcpy(runtime->buffer + runtime->hw_ptr, buffer, count1);
		runtime->hw_ptr += count1;
		runtime->hw_ptr %= runtime->buffer_size;
		runtime->avail += count1;
		count -= count1;
		result += count1;
		if (count > 0) {
			buffer += count1;
			count1 = count;
			if (count1 > (int)(runtime->buffer_size - runtime->avail)) {
				count1 = runtime->buffer_size - runtime->avail;
				runtime->xruns += count - count1;
			}
			if (count1 > 0) {
				memcpy(runtime->buffer, buffer, count1);
				runtime->hw_ptr = count1;
				runtime->avail += count1;
				result += count1;
			}
		}
	}
	if (result > 0) {
		if (runtime->event)
944
			schedule_work(&runtime->event_work);
L
Linus Torvalds 已提交
945 946 947 948 949 950
		else if (snd_rawmidi_ready(substream))
			wake_up(&runtime->sleep);
	}
	spin_unlock_irqrestore(&runtime->lock, flags);
	return result;
}
951
EXPORT_SYMBOL(snd_rawmidi_receive);
L
Linus Torvalds 已提交
952

953
static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream,
954 955
				     unsigned char __user *userbuf,
				     unsigned char *kernelbuf, long count)
L
Linus Torvalds 已提交
956 957 958
{
	unsigned long flags;
	long result = 0, count1;
959
	struct snd_rawmidi_runtime *runtime = substream->runtime;
960
	unsigned long appl_ptr;
L
Linus Torvalds 已提交
961

962
	spin_lock_irqsave(&runtime->lock, flags);
L
Linus Torvalds 已提交
963 964 965 966 967 968
	while (count > 0 && runtime->avail) {
		count1 = runtime->buffer_size - runtime->appl_ptr;
		if (count1 > count)
			count1 = count;
		if (count1 > (int)runtime->avail)
			count1 = runtime->avail;
969 970 971 972 973 974 975

		/* update runtime->appl_ptr before unlocking for userbuf */
		appl_ptr = runtime->appl_ptr;
		runtime->appl_ptr += count1;
		runtime->appl_ptr %= runtime->buffer_size;
		runtime->avail -= count1;

976
		if (kernelbuf)
977
			memcpy(kernelbuf + result, runtime->buffer + appl_ptr, count1);
978
		if (userbuf) {
L
Linus Torvalds 已提交
979
			spin_unlock_irqrestore(&runtime->lock, flags);
980
			if (copy_to_user(userbuf + result,
981
					 runtime->buffer + appl_ptr, count1)) {
L
Linus Torvalds 已提交
982 983 984 985 986 987 988
				return result > 0 ? result : -EFAULT;
			}
			spin_lock_irqsave(&runtime->lock, flags);
		}
		result += count1;
		count -= count1;
	}
989
	spin_unlock_irqrestore(&runtime->lock, flags);
L
Linus Torvalds 已提交
990 991 992
	return result;
}

993 994
long snd_rawmidi_kernel_read(struct snd_rawmidi_substream *substream,
			     unsigned char *buf, long count)
L
Linus Torvalds 已提交
995 996
{
	snd_rawmidi_input_trigger(substream, 1);
997
	return snd_rawmidi_kernel_read1(substream, NULL/*userbuf*/, buf, count);
L
Linus Torvalds 已提交
998
}
999
EXPORT_SYMBOL(snd_rawmidi_kernel_read);
L
Linus Torvalds 已提交
1000

1001 1002
static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t count,
				loff_t *offset)
L
Linus Torvalds 已提交
1003 1004 1005
{
	long result;
	int count1;
1006 1007 1008
	struct snd_rawmidi_file *rfile;
	struct snd_rawmidi_substream *substream;
	struct snd_rawmidi_runtime *runtime;
L
Linus Torvalds 已提交
1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019

	rfile = file->private_data;
	substream = rfile->input;
	if (substream == NULL)
		return -EIO;
	runtime = substream->runtime;
	snd_rawmidi_input_trigger(substream, 1);
	result = 0;
	while (count > 0) {
		spin_lock_irq(&runtime->lock);
		while (!snd_rawmidi_ready(substream)) {
1020
			wait_queue_entry_t wait;
1021

L
Linus Torvalds 已提交
1022 1023 1024 1025 1026 1027 1028 1029 1030 1031
			if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) {
				spin_unlock_irq(&runtime->lock);
				return result > 0 ? result : -EAGAIN;
			}
			init_waitqueue_entry(&wait, current);
			add_wait_queue(&runtime->sleep, &wait);
			set_current_state(TASK_INTERRUPTIBLE);
			spin_unlock_irq(&runtime->lock);
			schedule();
			remove_wait_queue(&runtime->sleep, &wait);
1032 1033
			if (rfile->rmidi->card->shutdown)
				return -ENODEV;
L
Linus Torvalds 已提交
1034 1035 1036 1037 1038 1039 1040
			if (signal_pending(current))
				return result > 0 ? result : -ERESTARTSYS;
			if (!runtime->avail)
				return result > 0 ? result : -EIO;
			spin_lock_irq(&runtime->lock);
		}
		spin_unlock_irq(&runtime->lock);
1041
		count1 = snd_rawmidi_kernel_read1(substream,
1042 1043 1044
						  (unsigned char __user *)buf,
						  NULL/*kernelbuf*/,
						  count);
L
Linus Torvalds 已提交
1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056
		if (count1 < 0)
			return result > 0 ? result : count1;
		result += count1;
		buf += count1;
		count -= count1;
	}
	return result;
}

/**
 * snd_rawmidi_transmit_empty - check whether the output buffer is empty
 * @substream: the rawmidi substream
1057 1058
 *
 * Return: 1 if the internal output buffer is empty, 0 if not.
L
Linus Torvalds 已提交
1059
 */
1060
int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream)
L
Linus Torvalds 已提交
1061
{
1062
	struct snd_rawmidi_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
1063 1064 1065 1066
	int result;
	unsigned long flags;

	if (runtime->buffer == NULL) {
1067 1068
		rmidi_dbg(substream->rmidi,
			  "snd_rawmidi_transmit_empty: output is not active!!!\n");
L
Linus Torvalds 已提交
1069 1070 1071 1072 1073
		return 1;
	}
	spin_lock_irqsave(&runtime->lock, flags);
	result = runtime->avail >= runtime->buffer_size;
	spin_unlock_irqrestore(&runtime->lock, flags);
1074
	return result;
L
Linus Torvalds 已提交
1075
}
1076
EXPORT_SYMBOL(snd_rawmidi_transmit_empty);
L
Linus Torvalds 已提交
1077 1078

/**
1079
 * __snd_rawmidi_transmit_peek - copy data from the internal buffer
L
Linus Torvalds 已提交
1080 1081 1082 1083
 * @substream: the rawmidi substream
 * @buffer: the buffer pointer
 * @count: data size to transfer
 *
1084
 * This is a variant of snd_rawmidi_transmit_peek() without spinlock.
L
Linus Torvalds 已提交
1085
 */
1086
int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
1087
			      unsigned char *buffer, int count)
L
Linus Torvalds 已提交
1088 1089
{
	int result, count1;
1090
	struct snd_rawmidi_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
1091 1092

	if (runtime->buffer == NULL) {
1093 1094
		rmidi_dbg(substream->rmidi,
			  "snd_rawmidi_transmit_peek: output is not active!!!\n");
L
Linus Torvalds 已提交
1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121
		return -EINVAL;
	}
	result = 0;
	if (runtime->avail >= runtime->buffer_size) {
		/* warning: lowlevel layer MUST trigger down the hardware */
		goto __skip;
	}
	if (count == 1) {	/* special case, faster code */
		*buffer = runtime->buffer[runtime->hw_ptr];
		result++;
	} else {
		count1 = runtime->buffer_size - runtime->hw_ptr;
		if (count1 > count)
			count1 = count;
		if (count1 > (int)(runtime->buffer_size - runtime->avail))
			count1 = runtime->buffer_size - runtime->avail;
		memcpy(buffer, runtime->buffer + runtime->hw_ptr, count1);
		count -= count1;
		result += count1;
		if (count > 0) {
			if (count > (int)(runtime->buffer_size - runtime->avail - count1))
				count = runtime->buffer_size - runtime->avail - count1;
			memcpy(buffer + count1, runtime->buffer, count);
			result += count;
		}
	}
      __skip:
1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148
	return result;
}
EXPORT_SYMBOL(__snd_rawmidi_transmit_peek);

/**
 * snd_rawmidi_transmit_peek - copy data from the internal buffer
 * @substream: the rawmidi substream
 * @buffer: the buffer pointer
 * @count: data size to transfer
 *
 * Copies data from the internal output buffer to the given buffer.
 *
 * Call this in the interrupt handler when the midi output is ready,
 * and call snd_rawmidi_transmit_ack() after the transmission is
 * finished.
 *
 * Return: The size of copied data, or a negative error code on failure.
 */
int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
			      unsigned char *buffer, int count)
{
	struct snd_rawmidi_runtime *runtime = substream->runtime;
	int result;
	unsigned long flags;

	spin_lock_irqsave(&runtime->lock, flags);
	result = __snd_rawmidi_transmit_peek(substream, buffer, count);
L
Linus Torvalds 已提交
1149 1150 1151
	spin_unlock_irqrestore(&runtime->lock, flags);
	return result;
}
1152
EXPORT_SYMBOL(snd_rawmidi_transmit_peek);
L
Linus Torvalds 已提交
1153 1154

/**
1155
 * __snd_rawmidi_transmit_ack - acknowledge the transmission
L
Linus Torvalds 已提交
1156
 * @substream: the rawmidi substream
1157
 * @count: the transferred count
L
Linus Torvalds 已提交
1158
 *
1159
 * This is a variant of __snd_rawmidi_transmit_ack() without spinlock.
L
Linus Torvalds 已提交
1160
 */
1161
int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count)
L
Linus Torvalds 已提交
1162
{
1163
	struct snd_rawmidi_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
1164 1165

	if (runtime->buffer == NULL) {
1166 1167
		rmidi_dbg(substream->rmidi,
			  "snd_rawmidi_transmit_ack: output is not active!!!\n");
L
Linus Torvalds 已提交
1168 1169
		return -EINVAL;
	}
1170
	snd_BUG_ON(runtime->avail + count > runtime->buffer_size);
L
Linus Torvalds 已提交
1171 1172 1173 1174 1175 1176 1177 1178 1179 1180
	runtime->hw_ptr += count;
	runtime->hw_ptr %= runtime->buffer_size;
	runtime->avail += count;
	substream->bytes += count;
	if (count > 0) {
		if (runtime->drain || snd_rawmidi_ready(substream))
			wake_up(&runtime->sleep);
	}
	return count;
}
1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204
EXPORT_SYMBOL(__snd_rawmidi_transmit_ack);

/**
 * snd_rawmidi_transmit_ack - acknowledge the transmission
 * @substream: the rawmidi substream
 * @count: the transferred count
 *
 * Advances the hardware pointer for the internal output buffer with
 * the given size and updates the condition.
 * Call after the transmission is finished.
 *
 * Return: The advanced size if successful, or a negative error code on failure.
 */
int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count)
{
	struct snd_rawmidi_runtime *runtime = substream->runtime;
	int result;
	unsigned long flags;

	spin_lock_irqsave(&runtime->lock, flags);
	result = __snd_rawmidi_transmit_ack(substream, count);
	spin_unlock_irqrestore(&runtime->lock, flags);
	return result;
}
1205
EXPORT_SYMBOL(snd_rawmidi_transmit_ack);
L
Linus Torvalds 已提交
1206 1207 1208 1209

/**
 * snd_rawmidi_transmit - copy from the buffer to the device
 * @substream: the rawmidi substream
T
Takashi Iwai 已提交
1210
 * @buffer: the buffer pointer
L
Linus Torvalds 已提交
1211
 * @count: the data size to transfer
1212
 *
L
Linus Torvalds 已提交
1213 1214
 * Copies data from the buffer to the device and advances the pointer.
 *
1215
 * Return: The copied size if successful, or a negative error code on failure.
L
Linus Torvalds 已提交
1216
 */
1217 1218
int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream,
			 unsigned char *buffer, int count)
L
Linus Torvalds 已提交
1219
{
1220 1221 1222 1223 1224
	struct snd_rawmidi_runtime *runtime = substream->runtime;
	int result;
	unsigned long flags;

	spin_lock_irqsave(&runtime->lock, flags);
1225
	if (!substream->opened)
1226 1227 1228 1229 1230 1231 1232 1233 1234 1235
		result = -EBADFD;
	else {
		count = __snd_rawmidi_transmit_peek(substream, buffer, count);
		if (count <= 0)
			result = count;
		else
			result = __snd_rawmidi_transmit_ack(substream, count);
	}
	spin_unlock_irqrestore(&runtime->lock, flags);
	return result;
L
Linus Torvalds 已提交
1236
}
1237
EXPORT_SYMBOL(snd_rawmidi_transmit);
L
Linus Torvalds 已提交
1238

1239
static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream,
1240 1241 1242
				      const unsigned char __user *userbuf,
				      const unsigned char *kernelbuf,
				      long count)
L
Linus Torvalds 已提交
1243 1244 1245
{
	unsigned long flags;
	long count1, result;
1246
	struct snd_rawmidi_runtime *runtime = substream->runtime;
1247
	unsigned long appl_ptr;
L
Linus Torvalds 已提交
1248

1249
	if (!kernelbuf && !userbuf)
1250 1251 1252
		return -EINVAL;
	if (snd_BUG_ON(!runtime->buffer))
		return -EINVAL;
L
Linus Torvalds 已提交
1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267

	result = 0;
	spin_lock_irqsave(&runtime->lock, flags);
	if (substream->append) {
		if ((long)runtime->avail < count) {
			spin_unlock_irqrestore(&runtime->lock, flags);
			return -EAGAIN;
		}
	}
	while (count > 0 && runtime->avail > 0) {
		count1 = runtime->buffer_size - runtime->appl_ptr;
		if (count1 > count)
			count1 = count;
		if (count1 > (long)runtime->avail)
			count1 = runtime->avail;
1268 1269 1270 1271 1272 1273 1274

		/* update runtime->appl_ptr before unlocking for userbuf */
		appl_ptr = runtime->appl_ptr;
		runtime->appl_ptr += count1;
		runtime->appl_ptr %= runtime->buffer_size;
		runtime->avail -= count1;

1275
		if (kernelbuf)
1276
			memcpy(runtime->buffer + appl_ptr,
1277 1278
			       kernelbuf + result, count1);
		else if (userbuf) {
L
Linus Torvalds 已提交
1279
			spin_unlock_irqrestore(&runtime->lock, flags);
1280
			if (copy_from_user(runtime->buffer + appl_ptr,
1281
					   userbuf + result, count1)) {
L
Linus Torvalds 已提交
1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298
				spin_lock_irqsave(&runtime->lock, flags);
				result = result > 0 ? result : -EFAULT;
				goto __end;
			}
			spin_lock_irqsave(&runtime->lock, flags);
		}
		result += count1;
		count -= count1;
	}
      __end:
	count1 = runtime->avail < runtime->buffer_size;
	spin_unlock_irqrestore(&runtime->lock, flags);
	if (count1)
		snd_rawmidi_output_trigger(substream, 1);
	return result;
}

1299 1300
long snd_rawmidi_kernel_write(struct snd_rawmidi_substream *substream,
			      const unsigned char *buf, long count)
L
Linus Torvalds 已提交
1301
{
1302
	return snd_rawmidi_kernel_write1(substream, NULL, buf, count);
L
Linus Torvalds 已提交
1303
}
1304
EXPORT_SYMBOL(snd_rawmidi_kernel_write);
L
Linus Torvalds 已提交
1305

1306 1307
static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf,
				 size_t count, loff_t *offset)
L
Linus Torvalds 已提交
1308 1309 1310
{
	long result, timeout;
	int count1;
1311 1312 1313
	struct snd_rawmidi_file *rfile;
	struct snd_rawmidi_runtime *runtime;
	struct snd_rawmidi_substream *substream;
L
Linus Torvalds 已提交
1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324

	rfile = file->private_data;
	substream = rfile->output;
	runtime = substream->runtime;
	/* we cannot put an atomic message to our buffer */
	if (substream->append && count > runtime->buffer_size)
		return -EIO;
	result = 0;
	while (count > 0) {
		spin_lock_irq(&runtime->lock);
		while (!snd_rawmidi_ready_append(substream, count)) {
1325
			wait_queue_entry_t wait;
1326

L
Linus Torvalds 已提交
1327 1328 1329 1330 1331 1332 1333 1334 1335 1336
			if (file->f_flags & O_NONBLOCK) {
				spin_unlock_irq(&runtime->lock);
				return result > 0 ? result : -EAGAIN;
			}
			init_waitqueue_entry(&wait, current);
			add_wait_queue(&runtime->sleep, &wait);
			set_current_state(TASK_INTERRUPTIBLE);
			spin_unlock_irq(&runtime->lock);
			timeout = schedule_timeout(30 * HZ);
			remove_wait_queue(&runtime->sleep, &wait);
1337 1338
			if (rfile->rmidi->card->shutdown)
				return -ENODEV;
L
Linus Torvalds 已提交
1339 1340 1341 1342 1343 1344 1345
			if (signal_pending(current))
				return result > 0 ? result : -ERESTARTSYS;
			if (!runtime->avail && !timeout)
				return result > 0 ? result : -EIO;
			spin_lock_irq(&runtime->lock);
		}
		spin_unlock_irq(&runtime->lock);
1346
		count1 = snd_rawmidi_kernel_write1(substream, buf, NULL, count);
L
Linus Torvalds 已提交
1347 1348 1349 1350 1351 1352 1353 1354
		if (count1 < 0)
			return result > 0 ? result : count1;
		result += count1;
		buf += count1;
		if ((size_t)count1 < count && (file->f_flags & O_NONBLOCK))
			break;
		count -= count1;
	}
1355
	if (file->f_flags & O_DSYNC) {
L
Linus Torvalds 已提交
1356 1357
		spin_lock_irq(&runtime->lock);
		while (runtime->avail != runtime->buffer_size) {
1358
			wait_queue_entry_t wait;
L
Linus Torvalds 已提交
1359
			unsigned int last_avail = runtime->avail;
1360

L
Linus Torvalds 已提交
1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377
			init_waitqueue_entry(&wait, current);
			add_wait_queue(&runtime->sleep, &wait);
			set_current_state(TASK_INTERRUPTIBLE);
			spin_unlock_irq(&runtime->lock);
			timeout = schedule_timeout(30 * HZ);
			remove_wait_queue(&runtime->sleep, &wait);
			if (signal_pending(current))
				return result > 0 ? result : -ERESTARTSYS;
			if (runtime->avail == last_avail && !timeout)
				return result > 0 ? result : -EIO;
			spin_lock_irq(&runtime->lock);
		}
		spin_unlock_irq(&runtime->lock);
	}
	return result;
}

1378
static __poll_t snd_rawmidi_poll(struct file *file, poll_table *wait)
L
Linus Torvalds 已提交
1379
{
1380 1381
	struct snd_rawmidi_file *rfile;
	struct snd_rawmidi_runtime *runtime;
A
Al Viro 已提交
1382
	__poll_t mask;
L
Linus Torvalds 已提交
1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396

	rfile = file->private_data;
	if (rfile->input != NULL) {
		runtime = rfile->input->runtime;
		snd_rawmidi_input_trigger(rfile->input, 1);
		poll_wait(file, &runtime->sleep, wait);
	}
	if (rfile->output != NULL) {
		runtime = rfile->output->runtime;
		poll_wait(file, &runtime->sleep, wait);
	}
	mask = 0;
	if (rfile->input != NULL) {
		if (snd_rawmidi_ready(rfile->input))
1397
			mask |= EPOLLIN | EPOLLRDNORM;
L
Linus Torvalds 已提交
1398 1399 1400
	}
	if (rfile->output != NULL) {
		if (snd_rawmidi_ready(rfile->output))
1401
			mask |= EPOLLOUT | EPOLLWRNORM;
L
Linus Torvalds 已提交
1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416
	}
	return mask;
}

/*
 */
#ifdef CONFIG_COMPAT
#include "rawmidi_compat.c"
#else
#define snd_rawmidi_ioctl_compat	NULL
#endif

/*
 */

1417 1418
static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
				       struct snd_info_buffer *buffer)
L
Linus Torvalds 已提交
1419
{
1420 1421 1422
	struct snd_rawmidi *rmidi;
	struct snd_rawmidi_substream *substream;
	struct snd_rawmidi_runtime *runtime;
L
Linus Torvalds 已提交
1423 1424 1425

	rmidi = entry->private_data;
	snd_iprintf(buffer, "%s\n\n", rmidi->name);
1426
	mutex_lock(&rmidi->open_mutex);
L
Linus Torvalds 已提交
1427
	if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT) {
1428 1429 1430
		list_for_each_entry(substream,
				    &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams,
				    list) {
L
Linus Torvalds 已提交
1431 1432 1433 1434 1435 1436
			snd_iprintf(buffer,
				    "Output %d\n"
				    "  Tx bytes     : %lu\n",
				    substream->number,
				    (unsigned long) substream->bytes);
			if (substream->opened) {
1437 1438 1439
				snd_iprintf(buffer,
				    "  Owner PID    : %d\n",
				    pid_vnr(substream->pid));
L
Linus Torvalds 已提交
1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451
				runtime = substream->runtime;
				snd_iprintf(buffer,
				    "  Mode         : %s\n"
				    "  Buffer size  : %lu\n"
				    "  Avail        : %lu\n",
				    runtime->oss ? "OSS compatible" : "native",
				    (unsigned long) runtime->buffer_size,
				    (unsigned long) runtime->avail);
			}
		}
	}
	if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_INPUT) {
1452 1453 1454
		list_for_each_entry(substream,
				    &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams,
				    list) {
L
Linus Torvalds 已提交
1455 1456 1457 1458 1459 1460
			snd_iprintf(buffer,
				    "Input %d\n"
				    "  Rx bytes     : %lu\n",
				    substream->number,
				    (unsigned long) substream->bytes);
			if (substream->opened) {
1461 1462 1463
				snd_iprintf(buffer,
					    "  Owner PID    : %d\n",
					    pid_vnr(substream->pid));
L
Linus Torvalds 已提交
1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474
				runtime = substream->runtime;
				snd_iprintf(buffer,
					    "  Buffer size  : %lu\n"
					    "  Avail        : %lu\n"
					    "  Overruns     : %lu\n",
					    (unsigned long) runtime->buffer_size,
					    (unsigned long) runtime->avail,
					    (unsigned long) runtime->xruns);
			}
		}
	}
1475
	mutex_unlock(&rmidi->open_mutex);
L
Linus Torvalds 已提交
1476 1477 1478 1479 1480 1481
}

/*
 *  Register functions
 */

1482
static const struct file_operations snd_rawmidi_f_ops = {
L
Linus Torvalds 已提交
1483 1484 1485 1486 1487
	.owner =	THIS_MODULE,
	.read =		snd_rawmidi_read,
	.write =	snd_rawmidi_write,
	.open =		snd_rawmidi_open,
	.release =	snd_rawmidi_release,
T
Takashi Iwai 已提交
1488
	.llseek =	no_llseek,
L
Linus Torvalds 已提交
1489 1490 1491 1492 1493
	.poll =		snd_rawmidi_poll,
	.unlocked_ioctl =	snd_rawmidi_ioctl,
	.compat_ioctl =	snd_rawmidi_ioctl_compat,
};

1494 1495
static int snd_rawmidi_alloc_substreams(struct snd_rawmidi *rmidi,
					struct snd_rawmidi_str *stream,
L
Linus Torvalds 已提交
1496 1497 1498
					int direction,
					int count)
{
1499
	struct snd_rawmidi_substream *substream;
L
Linus Torvalds 已提交
1500 1501 1502
	int idx;

	for (idx = 0; idx < count; idx++) {
1503
		substream = kzalloc(sizeof(*substream), GFP_KERNEL);
1504
		if (!substream)
L
Linus Torvalds 已提交
1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515
			return -ENOMEM;
		substream->stream = direction;
		substream->number = idx;
		substream->rmidi = rmidi;
		substream->pstr = stream;
		list_add_tail(&substream->list, &stream->substreams);
		stream->substream_count++;
	}
	return 0;
}

1516 1517 1518 1519 1520
static void release_rawmidi_device(struct device *dev)
{
	kfree(container_of(dev, struct snd_rawmidi, dev));
}

L
Linus Torvalds 已提交
1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532
/**
 * snd_rawmidi_new - create a rawmidi instance
 * @card: the card instance
 * @id: the id string
 * @device: the device index
 * @output_count: the number of output streams
 * @input_count: the number of input streams
 * @rrawmidi: the pointer to store the new rawmidi instance
 *
 * Creates a new rawmidi instance.
 * Use snd_rawmidi_set_ops() to set the operators to the new instance.
 *
1533
 * Return: Zero if successful, or a negative error code on failure.
L
Linus Torvalds 已提交
1534
 */
1535
int snd_rawmidi_new(struct snd_card *card, char *id, int device,
L
Linus Torvalds 已提交
1536
		    int output_count, int input_count,
1537
		    struct snd_rawmidi **rrawmidi)
L
Linus Torvalds 已提交
1538
{
1539
	struct snd_rawmidi *rmidi;
L
Linus Torvalds 已提交
1540
	int err;
1541
	static struct snd_device_ops ops = {
L
Linus Torvalds 已提交
1542 1543 1544 1545 1546
		.dev_free = snd_rawmidi_dev_free,
		.dev_register = snd_rawmidi_dev_register,
		.dev_disconnect = snd_rawmidi_dev_disconnect,
	};

1547 1548 1549 1550
	if (snd_BUG_ON(!card))
		return -ENXIO;
	if (rrawmidi)
		*rrawmidi = NULL;
1551
	rmidi = kzalloc(sizeof(*rmidi), GFP_KERNEL);
1552
	if (!rmidi)
L
Linus Torvalds 已提交
1553 1554 1555
		return -ENOMEM;
	rmidi->card = card;
	rmidi->device = device;
1556
	mutex_init(&rmidi->open_mutex);
L
Linus Torvalds 已提交
1557
	init_waitqueue_head(&rmidi->open_wait);
1558 1559 1560
	INIT_LIST_HEAD(&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams);
	INIT_LIST_HEAD(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams);

L
Linus Torvalds 已提交
1561 1562
	if (id != NULL)
		strlcpy(rmidi->id, id, sizeof(rmidi->id));
1563 1564 1565 1566 1567

	snd_device_initialize(&rmidi->dev, card);
	rmidi->dev.release = release_rawmidi_device;
	dev_set_name(&rmidi->dev, "midiC%iD%i", card->number, device);

1568 1569 1570 1571
	err = snd_rawmidi_alloc_substreams(rmidi,
					   &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT],
					   SNDRV_RAWMIDI_STREAM_INPUT,
					   input_count);
1572 1573
	if (err < 0)
		goto error;
1574 1575 1576 1577
	err = snd_rawmidi_alloc_substreams(rmidi,
					   &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT],
					   SNDRV_RAWMIDI_STREAM_OUTPUT,
					   output_count);
1578 1579
	if (err < 0)
		goto error;
1580
	err = snd_device_new(card, SNDRV_DEV_RAWMIDI, rmidi, &ops);
1581 1582 1583
	if (err < 0)
		goto error;

1584 1585
	if (rrawmidi)
		*rrawmidi = rmidi;
L
Linus Torvalds 已提交
1586
	return 0;
1587 1588 1589 1590

 error:
	snd_rawmidi_free(rmidi);
	return err;
L
Linus Torvalds 已提交
1591
}
1592
EXPORT_SYMBOL(snd_rawmidi_new);
L
Linus Torvalds 已提交
1593

1594
static void snd_rawmidi_free_substreams(struct snd_rawmidi_str *stream)
L
Linus Torvalds 已提交
1595
{
1596
	struct snd_rawmidi_substream *substream;
L
Linus Torvalds 已提交
1597 1598

	while (!list_empty(&stream->substreams)) {
1599
		substream = list_entry(stream->substreams.next, struct snd_rawmidi_substream, list);
L
Linus Torvalds 已提交
1600 1601 1602 1603 1604
		list_del(&substream->list);
		kfree(substream);
	}
}

1605
static int snd_rawmidi_free(struct snd_rawmidi *rmidi)
L
Linus Torvalds 已提交
1606
{
1607 1608
	if (!rmidi)
		return 0;
1609 1610 1611 1612 1613 1614 1615 1616

	snd_info_free_entry(rmidi->proc_entry);
	rmidi->proc_entry = NULL;
	mutex_lock(&register_mutex);
	if (rmidi->ops && rmidi->ops->dev_unregister)
		rmidi->ops->dev_unregister(rmidi);
	mutex_unlock(&register_mutex);

L
Linus Torvalds 已提交
1617 1618 1619 1620
	snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]);
	snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]);
	if (rmidi->private_free)
		rmidi->private_free(rmidi);
1621
	put_device(&rmidi->dev);
L
Linus Torvalds 已提交
1622 1623 1624
	return 0;
}

1625
static int snd_rawmidi_dev_free(struct snd_device *device)
L
Linus Torvalds 已提交
1626
{
1627
	struct snd_rawmidi *rmidi = device->device_data;
1628

L
Linus Torvalds 已提交
1629 1630 1631
	return snd_rawmidi_free(rmidi);
}

1632
#if IS_ENABLED(CONFIG_SND_SEQUENCER)
1633
static void snd_rawmidi_dev_seq_free(struct snd_seq_device *device)
L
Linus Torvalds 已提交
1634
{
1635
	struct snd_rawmidi *rmidi = device->private_data;
1636

L
Linus Torvalds 已提交
1637 1638 1639 1640
	rmidi->seq_dev = NULL;
}
#endif

1641
static int snd_rawmidi_dev_register(struct snd_device *device)
L
Linus Torvalds 已提交
1642
{
1643
	int err;
1644
	struct snd_info_entry *entry;
L
Linus Torvalds 已提交
1645
	char name[16];
1646
	struct snd_rawmidi *rmidi = device->device_data;
L
Linus Torvalds 已提交
1647 1648 1649

	if (rmidi->device >= SNDRV_RAWMIDI_DEVICES)
		return -ENOMEM;
1650
	err = 0;
1651
	mutex_lock(&register_mutex);
1652 1653 1654 1655
	if (snd_rawmidi_search(rmidi->card, rmidi->device))
		err = -EBUSY;
	else
		list_add_tail(&rmidi->list, &snd_rawmidi_devices);
1656
	mutex_unlock(&register_mutex);
1657 1658 1659
	if (err < 0)
		return err;

1660 1661 1662
	err = snd_register_device(SNDRV_DEVICE_TYPE_RAWMIDI,
				  rmidi->card, rmidi->device,
				  &snd_rawmidi_f_ops, rmidi, &rmidi->dev);
1663 1664
	if (err < 0) {
		rmidi_err(rmidi, "unable to register\n");
1665
		goto error;
L
Linus Torvalds 已提交
1666
	}
1667 1668 1669 1670
	if (rmidi->ops && rmidi->ops->dev_register) {
		err = rmidi->ops->dev_register(rmidi);
		if (err < 0)
			goto error_unregister;
L
Linus Torvalds 已提交
1671 1672 1673 1674 1675
	}
#ifdef CONFIG_SND_OSSEMUL
	rmidi->ossreg = 0;
	if ((int)rmidi->device == midi_map[rmidi->card->number]) {
		if (snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI,
1676
					    rmidi->card, 0, &snd_rawmidi_f_ops,
1677
					    rmidi) < 0) {
1678 1679 1680
			rmidi_err(rmidi,
				  "unable to register OSS rawmidi device %i:%i\n",
				  rmidi->card->number, 0);
L
Linus Torvalds 已提交
1681 1682 1683 1684 1685 1686 1687 1688 1689
		} else {
			rmidi->ossreg++;
#ifdef SNDRV_OSS_INFO_DEV_MIDI
			snd_oss_info_register(SNDRV_OSS_INFO_DEV_MIDI, rmidi->card->number, rmidi->name);
#endif
		}
	}
	if ((int)rmidi->device == amidi_map[rmidi->card->number]) {
		if (snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI,
1690
					    rmidi->card, 1, &snd_rawmidi_f_ops,
1691
					    rmidi) < 0) {
1692 1693 1694
			rmidi_err(rmidi,
				  "unable to register OSS rawmidi device %i:%i\n",
				  rmidi->card->number, 1);
L
Linus Torvalds 已提交
1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710
		} else {
			rmidi->ossreg++;
		}
	}
#endif /* CONFIG_SND_OSSEMUL */
	sprintf(name, "midi%d", rmidi->device);
	entry = snd_info_create_card_entry(rmidi->card, name, rmidi->card->proc_root);
	if (entry) {
		entry->private_data = rmidi;
		entry->c.text.read = snd_rawmidi_proc_info_read;
		if (snd_info_register(entry) < 0) {
			snd_info_free_entry(entry);
			entry = NULL;
		}
	}
	rmidi->proc_entry = entry;
1711
#if IS_ENABLED(CONFIG_SND_SEQUENCER)
L
Linus Torvalds 已提交
1712 1713 1714 1715 1716 1717 1718 1719 1720 1721
	if (!rmidi->ops || !rmidi->ops->dev_register) { /* own registration mechanism */
		if (snd_seq_device_new(rmidi->card, rmidi->device, SNDRV_SEQ_DEV_ID_MIDISYNTH, 0, &rmidi->seq_dev) >= 0) {
			rmidi->seq_dev->private_data = rmidi;
			rmidi->seq_dev->private_free = snd_rawmidi_dev_seq_free;
			sprintf(rmidi->seq_dev->name, "MIDI %d-%d", rmidi->card->number, rmidi->device);
			snd_device_register(rmidi->card, rmidi->seq_dev);
		}
	}
#endif
	return 0;
1722 1723 1724 1725 1726 1727 1728 1729

 error_unregister:
	snd_unregister_device(&rmidi->dev);
 error:
	mutex_lock(&register_mutex);
	list_del(&rmidi->list);
	mutex_unlock(&register_mutex);
	return err;
L
Linus Torvalds 已提交
1730 1731
}

1732
static int snd_rawmidi_dev_disconnect(struct snd_device *device)
L
Linus Torvalds 已提交
1733
{
1734
	struct snd_rawmidi *rmidi = device->device_data;
1735
	int dir;
L
Linus Torvalds 已提交
1736

1737
	mutex_lock(&register_mutex);
1738 1739
	mutex_lock(&rmidi->open_mutex);
	wake_up(&rmidi->open_wait);
1740
	list_del_init(&rmidi->list);
1741 1742
	for (dir = 0; dir < 2; dir++) {
		struct snd_rawmidi_substream *s;
1743

1744 1745 1746 1747 1748 1749
		list_for_each_entry(s, &rmidi->streams[dir].substreams, list) {
			if (s->runtime)
				wake_up(&s->runtime->sleep);
		}
	}

L
Linus Torvalds 已提交
1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762
#ifdef CONFIG_SND_OSSEMUL
	if (rmidi->ossreg) {
		if ((int)rmidi->device == midi_map[rmidi->card->number]) {
			snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI, rmidi->card, 0);
#ifdef SNDRV_OSS_INFO_DEV_MIDI
			snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIDI, rmidi->card->number);
#endif
		}
		if ((int)rmidi->device == amidi_map[rmidi->card->number])
			snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI, rmidi->card, 1);
		rmidi->ossreg = 0;
	}
#endif /* CONFIG_SND_OSSEMUL */
1763
	snd_unregister_device(&rmidi->dev);
1764
	mutex_unlock(&rmidi->open_mutex);
1765
	mutex_unlock(&register_mutex);
1766
	return 0;
L
Linus Torvalds 已提交
1767 1768 1769 1770 1771 1772 1773 1774 1775 1776
}

/**
 * snd_rawmidi_set_ops - set the rawmidi operators
 * @rmidi: the rawmidi instance
 * @stream: the stream direction, SNDRV_RAWMIDI_STREAM_XXX
 * @ops: the operator table
 *
 * Sets the rawmidi operators for the given stream direction.
 */
1777
void snd_rawmidi_set_ops(struct snd_rawmidi *rmidi, int stream,
1778
			 const struct snd_rawmidi_ops *ops)
L
Linus Torvalds 已提交
1779
{
1780
	struct snd_rawmidi_substream *substream;
1781

1782
	list_for_each_entry(substream, &rmidi->streams[stream].substreams, list)
L
Linus Torvalds 已提交
1783 1784
		substream->ops = ops;
}
1785
EXPORT_SYMBOL(snd_rawmidi_set_ops);
L
Linus Torvalds 已提交
1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800

/*
 *  ENTRY functions
 */

static int __init alsa_rawmidi_init(void)
{

	snd_ctl_register_ioctl(snd_rawmidi_control_ioctl);
	snd_ctl_register_ioctl_compat(snd_rawmidi_control_ioctl);
#ifdef CONFIG_SND_OSSEMUL
	{ int i;
	/* check device map table */
	for (i = 0; i < SNDRV_CARDS; i++) {
		if (midi_map[i] < 0 || midi_map[i] >= SNDRV_RAWMIDI_DEVICES) {
1801 1802
			pr_err("ALSA: rawmidi: invalid midi_map[%d] = %d\n",
			       i, midi_map[i]);
L
Linus Torvalds 已提交
1803 1804 1805
			midi_map[i] = 0;
		}
		if (amidi_map[i] < 0 || amidi_map[i] >= SNDRV_RAWMIDI_DEVICES) {
1806 1807
			pr_err("ALSA: rawmidi: invalid amidi_map[%d] = %d\n",
			       i, amidi_map[i]);
L
Linus Torvalds 已提交
1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823
			amidi_map[i] = 1;
		}
	}
	}
#endif /* CONFIG_SND_OSSEMUL */
	return 0;
}

static void __exit alsa_rawmidi_exit(void)
{
	snd_ctl_unregister_ioctl(snd_rawmidi_control_ioctl);
	snd_ctl_unregister_ioctl_compat(snd_rawmidi_control_ioctl);
}

module_init(alsa_rawmidi_init)
module_exit(alsa_rawmidi_exit)