/* $ZEL: sis1100_open.c,v 1.5 2004/02/10 16:29:44 wuestner Exp $ */ /* * Copyright (c) 2001-2004 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 "sis1100_sc.h" static void _sis1100_open(struct sis1100_softc* sc, struct sis1100_fdata* fd, int idx) { SEM_LOCK(sc->sem_fdata_list); list_add(&fd->list, &sc->fdata_list_head); SEM_UNLOCK(sc->sem_fdata_list); 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->last_prot_err=0; fd->sig=0; fd->owned_irqs=0; /* useless for sdram and sharc */ fd->mindmalen_r=24; fd->mindmalen_w=400; fd->mmapdma.valid=0; sc->fdatalist[idx]=fd; } #ifdef __NetBSD__ int sis1100_open(dev_t dev, int flag, int mode, struct proc *p) { struct sis1100_softc* sc; struct sis1100_fdata* fd; unsigned int _minor=minor(dev); unsigned int card=(_minor&sis1100_MINORCARDMASK)>>sis1100_MINORCARDSHIFT; unsigned int subdev=(_minor&sis1100_MINORTYPEMASK)>>sis1100_MINORTYPESHIFT; unsigned int idx=_minor&(sis1100_MINORUTMASK); if (card >= sis1100cfdriver.cd_ndevs || !sis1100cfdriver.cd_devs[card]) { pINFOsc("open: _minor=%d card=%d idx=%d, returning ENXIO", _minor, card, idx); return ENXIO; } sc=SIS1100SC(dev); if (sc->fdatalist[idx]) return EBUSY; fd=malloc(sizeof(struct sis1100_fdata), M_DEVBUF, M_WAITOK); if (!fd) return ENOMEM; fd->p=p; fd->sig=0; fd->subdev=subdev; simple_lock(&sc->lock_sc_inuse); sc->sc_inuse++; simple_unlock(&sc->sc_inuse); sc->fdatalist[idx]=fd; _sis1100_open(sc, fd, idx); return 0; } #elif __linux__ int sis1100_open(struct inode *inode, struct file *file) { struct sis1100_softc* sc; struct sis1100_fdata* fd; unsigned int _minor=iminor(inode); unsigned int card=(_minor&sis1100_MINORCARDMASK)>>sis1100_MINORCARDSHIFT; unsigned int subdev=(_minor&sis1100_MINORTYPEMASK)>>sis1100_MINORTYPESHIFT; unsigned int idx=_minor&sis1100_MINORUTMASK; if (card >= sis1100_MAXCARDS || !sis1100_devdata[card]) { printk(KERN_INFO "sis1100 open: returning ENXIO\n"); return -ENXIO; /*ENODEV*/ } sc=sis1100_devdata[card]; if (sc->fdatalist[idx]) { return -EBUSY; } fd=kmalloc(sizeof(struct sis1100_fdata), GFP_KERNEL); if (!fd) return -ENOMEM; fd->sc=sc; fd->subdev=subdev; file->private_data = fd; _sis1100_open(sc, fd, idx); return 0; } #endif static void _sis1100_close(struct sis1100_softc* sc, struct sis1100_fdata* fd, int idx) { u_int32_t mask; switch (sc->remote_hw) { case sis1100_hw_vme: if (fd->owned_irqs & SIS3100_IRQS) { sis3100writeremreg(sc, vme_irq_sc, (fd->owned_irqs & SIS3100_IRQS)<<16, 0); } break; case sis1100_hw_camac: if (fd->owned_irqs & SIS5100_IRQS) { /*sis5100writeremreg(sc, vme_irq_sc, (fd->owned_irqs & SIS5100_IRQS)<<16, 0);*/ } break; case sis1100_hw_pci: break; /* do nothing */ case sis1100_hw_f1: break; /* do nothing */ case sis1100_hw_vertex: break; /* do nothing */ case sis1100_hw_invalid: break; /* do nothing */ } mask=0; if (fd->owned_irqs & SIS1100_FRONT_IRQS) { mask|=(fd->owned_irqs & SIS1100_FRONT_IRQS)>>4; } if (fd->owned_irqs & SIS1100_MBX0_IRQ) { mask|=irq_mbx0; } if (mask) sis1100_disable_irq(sc, 0, mask); /*if (fd->mmapdma.valid) sis1100_dma_free(sc, fd, 0);*/ SEM_LOCK(sc->sem_fdata_list); list_del(&fd->list); SEM_UNLOCK(sc->sem_fdata_list); sc->fdatalist[idx]=0; } #ifdef __NetBSD__ int sis1100_close(dev_t dev, int flag, int mode, struct proc *p) { struct sis1100_softc* sc=SIS1100SC(dev); struct sis1100_fdata* fd=SIS1100FD(dev); unsigned int minor=minor(dev); unsigned int idx=minor&(sis1100_MINORUTMASK); _sis1100_close(sc, fd, idx); free(fd, M_DEVBUF); simple_lock(&sc->lock_sc_inuse); sc->sc_inuse--; simple_unlock(&sc->sc_inuse); return 0; } #elif __linux__ int sis1100_release(struct inode *inode, struct file *file) { struct sis1100_softc* sc=SIS1100SC(file); struct sis1100_fdata* fd=SIS1100FD(file); unsigned int _minor=iminor(inode); unsigned int idx=_minor&(sis1100_MINORUTMASK); _sis1100_close(sc, fd, idx); kfree(fd); return 0; } #endif