/* $ZEL: sis1100_mmap.c,v 1.3 2002/05/29 15:54:24 wuestner Exp $ */

/*
 * Copyright (c) 2001
 * 	Peter Wuestner.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions, and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/wrapper.h>
#include <linux/pci.h>
#include <asm/uaccess.h>

#include <dev/pci/sis1100var.h>

int
sis1100_mmap(struct file * file, struct vm_area_struct * vma)
{
    struct SIS1100_softc *sc = SIS1100SC(file);
    unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
    unsigned long size = vma->vm_end-vma->vm_start;
    unsigned long memoffset;
    int error;

    if (offset+size>PAGE_ALIGN(sc->plxlocallen1))
    	    return -EINVAL;
    memoffset=pci_resource_start(sc->pcidev, 3)+offset;
    vma->vm_flags |= VM_RESERVED;
    vma->vm_flags |= VM_IO;

    if ((error=remap_page_range(vma->vm_start, memoffset,
    	    size, vma->vm_page_prot))!=0)
    	return error;
    return 0;
}

#if 0
int
sis1100_mmap(struct file * file, struct vm_area_struct * vma)
{
    struct SIS1100_softc *sc = SIS1100SC(file);
    unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
    unsigned long size = vma->vm_end-vma->vm_start;
    unsigned long spaceoffset, memoffset;
    int error;
/*
    printk(KERN_INFO "SIS1100: mmap(offset=0x%lx, size=0x%lx)\n", offset, size);
*/
    /* is it plx-space? */
    if (offset<sc->plxmemlen) {
    	printk(KERN_INFO "SIS1100: map plxmem, offs=0x%lx\n", offset);
    	if (offset+size>PAGE_ALIGN(sc->plxmemlen)) {
    	    printk(KERN_INFO "offs+size=0x%lx, plxmemlen=0x%x\n",
    	    	offset+size, sc->plxmemlen);
    	    return -EINVAL;
    	}
    	memoffset=pci_resource_start(sc->pcidev, 0)+offset;
        /* do not allow mapping of plxspace */
        return -EINVAL;
    } else if ((offset>=PAGE_ALIGN(sc->plxmemlen))
	    	&& (offset<PAGE_ALIGN(sc->plxmemlen)+sc->plxlocallen0)) {
    	spaceoffset=offset-PAGE_ALIGN(sc->plxmemlen);
      /*printk(KERN_INFO "SIS1100: map local0, offs=0x%lx\n", spaceoffset);*/
    	if (spaceoffset+size>PAGE_ALIGN(sc->plxlocallen0))
    	    return -EINVAL;
    	memoffset=pci_resource_start(sc->pcidev, 2)+spaceoffset;
    } else if ((offset>=PAGE_ALIGN(sc->plxmemlen)+
    	    	    	PAGE_ALIGN(sc->plxlocallen0))
	    	&& (offset<PAGE_ALIGN(sc->plxmemlen)+
    	    	    	PAGE_ALIGN(sc->plxlocallen0)+sc->plxlocallen1)) {
    	spaceoffset=offset-PAGE_ALIGN(sc->plxmemlen)-
    	    	    	PAGE_ALIGN(sc->plxlocallen0);
      /*printk(KERN_INFO "SIS1100: map local1, offs=0x%lx\n", spaceoffset);*/
    	if (spaceoffset+size>PAGE_ALIGN(sc->plxlocallen1))
    	    return -EINVAL;
    	memoffset=pci_resource_start(sc->pcidev, 3)+spaceoffset;
    } else {
    	return -EINVAL;
    }
/*
    printk(KERN_INFO "call remap with memoffset=0x%lx, size=0x%lx\n",
    	    memoffset, size);
*/
    /* Don't try to swap out physical pages.. */
    vma->vm_flags |= VM_RESERVED;
    /*
    * Don't dump addresses that are not real memory to a core file.
    */
    vma->vm_flags |= VM_IO;

    if ((error=remap_page_range(vma->vm_start, memoffset,
    	    size, vma->vm_page_prot))!=0)
    	return error;
    return 0;
}
#endif
