/* $ZEL: sis1100_open.c,v 1.10 2002/03/19 18:47:06 wuestner Exp $ */

/*
 * Copyright (c) 2001
 * 	Matthias Drochner, 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/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 <dev/pci/sis1100var.h>

static int
_sis1100_open(struct inode *inode, struct file *file,
        enum sis1100_subdevs subdev)
{
    unsigned int unit;
    struct SIS1100_softc* sc;
    struct SIS1100_fdata* fd;

    if (file->private_data) {
        unit=(unsigned long int)file->private_data&0xff;
    } else {
        printk(KERN_INFO "SIS1100[%d] open: pid=%d\n",
                MINOR(inode->i_rdev), current->pid);
        unit = MINOR(inode->i_rdev);
    }

    if (unit >= MAX_SIS1100_DEVICES) return (-ENODEV);
    sc = SIS1100_devdata[unit];
    if (!sc) return (-ENODEV);

    fd=kmalloc(sizeof(struct SIS1100_fdata), GFP_KERNEL);
    if (!fd) return -ENOMEM;
    fd->sc=sc;
    fd->subdev=subdev;
    file->private_data = fd;
    down(&sc->sem_fdata_list);
    list_add(&fd->list, &sc->fdata_list_head);
    up(&sc->sem_fdata_list);

    fd->big_endian=1;
    fd->fifo_mode=0;          /* can't be changed for sdram and sharc */
    fd->vmespace_am=9;        /* useless for sdram and sharc */
    fd->vmespace_datasize=4;  /* useless for sdram and sharc */
    /*fd->vmespace_sizemask=3;*/  /* useless for sdram and sharc */
    fd->last_prot_err=0;
    fd->sig=0;
    fd->owned_irqs=0;         /* useless for sdram and sharc */
    fd->mindmalen_r=24;
    fd->mindmalen_w=400;
    return 0;
}

int
sis1100_open(struct inode *inode, struct file *file)
{
    return _sis1100_open(inode, file, sis1100_subdev_vme);
}

int
sis1100sdram_open(struct inode *inode, struct file *file)
{
    return _sis1100_open(inode, file, sis1100_subdev_ram);
}

int
sis1100sharc_open(struct inode *inode, struct file *file)
{
    return _sis1100_open(inode, file, sis1100_subdev_sharc);
}

int
sis1100_release(struct inode *inode, struct file *file)
{
        struct SIS1100_softc* sc=SIS1100SC(file);
        struct SIS1100_fdata* fd=SIS1100FD(file);

        printk(KERN_INFO "SIS1100[%d] release: pid=%d\n",
                MINOR(inode->i_rdev), current->pid);
        if (fd->owned_irqs & SIS3100_IRQS)
                sis3100writereg(sc, vme_irq_sc,
                        (fd->owned_irqs & SIS3100_IRQS)<<16, 0);
        down(&sc->sem_fdata_list);
        list_del(&fd->list);
        up(&sc->sem_fdata_list);

        kfree(fd);
        return 0;
}
