/*
 *  VMA management
 *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
 *
 *
 *   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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include "../include/driver.h"

static snd_vma_t * snd_vma_first = NULL;

static snd_vma_t * snd_vma_find(struct vm_area_struct *area, snd_vma_t ** prev)
{
	snd_vma_t * vma;

	if (prev)
		*prev = NULL;
	for (vma = snd_vma_first; vma; vma = vma->next) {
		if (vma->area == area)
			return vma;
		*prev = vma;
	}
	snd_printd("snd_vma: oops, area 0x%lx not found\n", (long)area);
	return NULL;
}

static void snd_vma_open(struct vm_area_struct *area)
{
#if 0
	MOD_INC_USE_COUNT;
#endif
}

static void snd_vma_close(struct vm_area_struct *area)
{
	snd_vma_t * vma, * prev;

	// printk("snd_vma_close: vm_area=0x%lx\n", (long)area);
	vma = snd_vma_find(area, &prev);
	if (vma == NULL)
		return;
	// printk("snd_vma_close: vma=0x%lx\n", (long)vma);
	if (prev) {
		prev->next = vma->next;
	} else {
		snd_vma_first = vma->next;
	}		
	if (vma->notify)
		vma->notify(vma->notify_client, vma->notify_data);
	snd_kfree(vma);
	MOD_DEC_USE_COUNT;
}

static struct vm_operations_struct snd_vma_ops =
{
	open:	snd_vma_open,
	close:	snd_vma_close,
};

void snd_vma_add(snd_vma_t * vma)
{
	if (vma == NULL || vma->area == NULL)
		return;
	// printk("snd_vma_add: vma = 0x%lx, vma->area = 0x%lx\n", (long)vma, (long)vma->area);
	vma->next = snd_vma_first;
	vma->area->vm_ops = &snd_vma_ops;
	snd_vma_first = vma;
	MOD_INC_USE_COUNT;
}

void snd_vma_disconnect(snd_vma_t * vma)
{
	if (vma == NULL)
		return;
	vma->notify = NULL;
	vma->notify_client = NULL;
}
