/* * IBM Smart Capture Card driver. * * Copyright (c) 1996 * Takeshi OHASHI and Yoshihisa NAKAGAWA. 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Takeshi OHASHI * and Yoshihisa NAKAGAWA. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY KOJI OKAMURA, TAKESHI OHASHI 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 TAKESHI OHASHI 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. * * Changed by Yoshihisa NAKAGAWA * Changed by Takeshi OHASHI * Changed by Hidetoshi KIMURA * Version 0.36, Nov 24, 1996. * */ #include "scc.h" #if NSCC > 0 #undef REMAP_MEM_WIN /* define to remap memory window */ #define PCCARD_MEM /* It is working now */ #ifdef REMAP_MEM_WIN #undef PCCARD_MEM #endif #ifdef PCCARD_MEM #undef REMAP_MEM_WIN #endif #define FREEBSD22 /* define for 2.2-SNAP */ #undef FREEBSD215R /* define for FreeBSD-2.1.5-R */ #undef FREEBSD210R /* define for FreeBSD-2.1.0-R */ #ifdef FREEBSD22 #undef FREEBSD215R #undef FREEBSD210R #undef BUGGY_UIO #endif #ifdef FREEBSD215R #undef FREEBSD210R #undef BUGGY_UIO #endif #ifdef FREEBSD210R #define FREEBSD215R #define BUGGY_UIO #endif #undef SOFT_INTR /* define to use splbio(), undef to use disable_intr() */ #define SCC_DEBUG 0 /* define to report infomation for debugging */ #include #include #include #include #include #include #include #include #include #ifdef DEVFS #include #endif /* DEVFS */ #include #include #include #include #ifdef ACTUALLY_LKM_NOT_KERNEL #include #include #include #endif /* ACTUALLY_LKM_NOT_KERNEL */ #include struct scc_softc { u_long flags; /* SCC_ACTIVE|SCC_OPEN */ caddr_t maddr; int msize; int iobase; int unit; struct proc *p; /* ? */ u_long signal_num; /* ? */ u_short irq; scc_card_t scc; int slot; /* PC-card slot */ int gone; /* PC-card removed */ #ifdef DEVFS void *devfs_token_scc; void *devfs_token_ctl; #endif } scc_softc[NSCC]; #define SCCMASK 0x7f #define CTLMASK 0x80 #define UNIT(dev) minor(dev)&SCCMASK #define ISCTL(dev) minor(dev)&CTLMASK static int scc_probe(struct isa_device *id); static int scc_attach(struct isa_device *id); struct isa_driver sccdriver = { scc_probe, scc_attach, "scc" }; #ifdef FREEBSD215R #define STATIC_CDEVSW #else /* FREEBSD215R */ static d_open_t scc_open; static d_close_t scc_close; static d_read_t scc_read; static d_write_t scc_write; static d_ioctl_t scc_ioctl; static d_select_t scc_select; static d_mmap_t scc_mmap; #define STATIC_CDEVSW static #define CDEV_MAJOR 76 static struct cdevsw scc_cdevsw = { scc_open, scc_close, scc_read, scc_write, /* 76 */ scc_ioctl, nostop, nullreset, nodevtotty, /* SCC */ scc_select, scc_mmap, NULL, "scc", NULL, -1 }; #endif /* FREEBSD215R */ /* PCCARD suport */ #include "card.h" #if NCARD > 0 #include #include #include #include #include #endif /* NCARD > 0 */ /* PCCARD Support */ #if NCARD > 0 /* * PC-Card (PCMCIA) specific code. */ static int scc_card_intr(struct pccard_devinfo *); /* Interrupt handler */ void sccunload(struct pccard_devinfo *); /* Disable driver */ void sccsuspend(struct pccard_devinfo *); /* Suspend driver */ static int sccinit(struct pccard_devinfo *, int); /* init device */ static int scc_probe_pccard(struct isa_device *devp); #ifdef ACTUALLY_LKM_NOT_KERNEL void sccintr(int unit); #endif /* ACTUALLY_LKM_NOT_KERNEL */ #ifdef PCCARD_MEM static struct pccard_devinfo *dev_tab[NSCC]; #endif /* PCCARD_MEM */ static int scc_already_init = 0; static int probed[NSCC]; static struct pccard_device scc_info = { "scc", sccinit, sccunload, scc_card_intr, /* sccsuspend, */ 0, /* Attributes - presently unused */ &bio_imask /* Interrupt mask for device */ /* This should also include net_imask?? */ }; DATA_SET(pccarddrv_set, scc_info); /* * Called when a power down is wanted. Shuts down the * device and configures the device as unavailable (but * still loaded...). A resume is done by calling * feinit with first=0. This is called when the user suspends * the system, or the APM code suspends the system. */ void sccsuspend(struct pccard_devinfo *devi) { struct scc_softc *sc=(struct scc_softc *)&scc_softc[devi->isahd.id_unit]; printf("scc%d: suspending\n", devi->isahd.id_unit); sc->gone = 1; } /* * Initialize the device - called from Slot manager. * if first is set, then initially check for * the device's existence before initialising it. * Once initialised, the device table may be set up. */ int sccinit(struct pccard_devinfo *devi, int first) { struct scc_softc *sc=(struct scc_softc *)&scc_softc[devi->isahd.id_unit]; static int already_sccinit[NSCC]; int unit = devi->isahd.id_unit; /* * validate unit number. */ if (unit >= NSCC) return(ENODEV); /* * Probe the device. If a value is returned, the * device was found at the location. */ if (first) { /* * Probe the device. If a value is returned, the * device was found at the location. */ #if SCC_DEBUG > 0 printf("Start Probe scc\n"); #endif #ifdef ACTUALLY_LKM_NOT_KERNEL if (!probed[unit]) { probed[unit] = 1; } #endif /* ACTUALLY_LKM_NOT_KERNEL */ if (scc_probe_pccard(&devi->isahd)==0) return(ENXIO); #if SCC_DEBUG > 0 printf("Start attach scc\n"); #endif if (scc_attach(&devi->isahd)==0) return(ENXIO); } /* * XXX TODO: * If it was already inited before, the device structure * should be already initialised. Here we should * reset (and possibly restart) the hardware, but * I am not sure of the best way to do this... */ already_sccinit[devi->isahd.id_unit] = 1; printf("scc%d: init\n", devi->isahd.id_unit); #ifdef PCCARD_MEM dev_tab[devi->isahd.id_unit] = devi; #endif /* PCCARD_MEM */ if (!first) { sc->gone = 0; #if 0 devi->slt->ctrl->reset(devi->slt); #endif printf("scc%d: resumed\n", unit); } sc->slot = devi->slt->slotnum; return(0); } /* * sccunload - unload the driver and clear the table. * XXX TODO: * This is called usually when the card is ejected, but * can be caused by the modunload of a controller driver. * The idea is reset the driver's view of the device * and ensure that any driver entry points such as * read and write do not hang. */ void sccunload(struct pccard_devinfo *devi) { struct scc_softc *ss=(struct scc_softc *)&scc_softc[devi->isahd.id_unit]; ss->flags &= ~SCC_ALIVE; ss->gone = 1; #if 0 #ifdef PCCARD_MEM dev_tab[devi->isahd.id_unit] = NULL; #endif /* PCCARD_MEM */ #endif #if 0 /* Ohashi */ #ifdef ACTUALLY_LKM_NOT_KERNEL --scc_already_init; #endif /* ACTUALLY_LKM_NOT_KERNEL */ #endif /* 0 Ohashi */ } /* * card_intr - Shared interrupt called from * front end of PC-Card handler. */ static int scc_card_intr(struct pccard_devinfo *devi) { sccintr(devi->isahd.id_unit); return(1); } /* * scc_probe_pccard - Probe routine for PC-Card */ static int scc_probe_pccard(struct isa_device *devp) { #if 0 struct scc_softc *ss=(struct scc_softc *)&scc_softc[devp->id_unit]; #endif #if SCC_DEBUG > 0 printf("scc_probe_pccard\n"); #endif #if 0 if (inb(ss->iobase) & 0x7f == 0x7f) { return (0); /* not found */ } #endif return (0x04); /* always found result when this is called */ } #endif /* NCARD > 0 */ int scc_probe(struct isa_device *devp) { #if NCARD > 0 #ifndef ACTUALLY_LKM_NOT_KERNEL ++scc_already_init; #endif /* !ACTUALLY_LKM_NOT_KERNEL */ if (!probed[devp->id_unit]) { probed[devp->id_unit] = 1; } #endif /* NCARD > 0 */ #if SCC_DEBUG > 0 printf("scc_card_probe\n"); #endif return 0; } int scc_attach(struct isa_device *devp) { struct scc_softc *ss=(struct scc_softc *)&scc_softc[devp->id_unit]; int unit = devp->id_unit; #if NCARD > 0 static int attached[NSCC]; #endif /* NCARD > 0 */ if (unit >= NSCC) return (0); if (!attached[unit]) { attached[unit] = 1; } ss->iobase = devp->id_iobase; ss->irq = devp->id_irq; ss->maddr = devp->id_maddr; ss->msize = devp->id_msize; ss->unit = devp->id_unit; ss->flags = SCC_ALIVE; ss->gone = 0; #if SCC_DEBUG > 0 if (ss->maddr == NULL) printf("scc iobase = %x, irq = %x, maddr = %x, msize = %x\n", ss->iobase, ss->irq, ss->maddr, ss->msize); else printf("scc iobase = %x, irq = %x, maddr = %x, msize = %x\n", ss->iobase, ss->irq, kvtop(ss->maddr), ss->msize); #endif #ifdef DEVFS /* devsw, minor, type, uid, gid, perm, fmt, ... */ ss->devfs_token_scc = devfs_add_devswf(&scc_cdevsw, unit, DV_CHR, UID_ROOT, GID_WHEEL, 0644, "scc%n", unit); ss->devfs_token_ctl = devfs_add_devswf(&scc_cdevsw, unit | CTLMASK, DV_CHR, UID_ROOT, GID_WHEEL, 0644, "sccctl%n", unit); #endif #if SCC_DEBUG > 0 printf("scc_attach\n"); #endif return 1; } STATIC_CDEVSW int scc_open(dev_t dev, int flags, int fmt, struct proc *p) { struct scc_softc *ss=(struct scc_softc *)&scc_softc[UNIT(dev)]; #ifdef PCCARD_MEM struct slot *slt; #endif /* PCCARD_MEM */ #ifdef SOFT_INTR int s; #endif /* SOFT_INTR */ #if SCC_DEBUG > 0 printf("scc_open\n"); #endif if (ss == NULL) return ENXIO; if (ss->gone) return ENXIO; if (ISCTL(dev)) return 0; #ifdef PCCARD_MEM slt = dev_tab[UNIT(dev)]->slt; if (slt == NULL || slt->state != filled) return (ENXIO); #endif /* PCCARD_MEM */ if (!(ss->flags & SCC_ALIVE)) return ENXIO; if (ss->flags & SCC_OPEN) return EBUSY; #ifdef SOFT_INTR s = splbio(); #else disable_intr(); #endif /* SOFT_INTR */ ss->flags |= SCC_OPEN; ss->p = 0; ss->signal_num = 0; ss->scc.geomet.width = SCC_NTSCWIDTH; ss->scc.geomet.height = SCC_NTSCHEIGHT; ss->scc.mode = SCC_NTSC; ss->scc.format = SCC_RGB565; InitVPX(ss->iobase, ss->scc.mode, 0, ss->scc.geomet.width, ss->scc.geomet.height, 1, ss->scc.format, UNIT(dev)); ss->scc.color.brightness = SCC_DEFBRIGHTNESS; ss->scc.color.contrast = SCC_DEFCONTRAST; ss->scc.color.saturation = SCC_DEFSATURATION; ss->scc.color.hue = SCC_DEFHUE; SetVPXColor(ss->scc.color.brightness, ss->scc.color.contrast, ss->scc.color.saturation, ss->scc.color.hue, UNIT(dev)); ss->scc.tv.tuntype = TUNETYPE; ss->scc.tv.channel = 7; ss->scc.tv.fine = 0; ss->scc.tv.country = 0; /* Japan:0 USA:1 */ SetTVChannel(ss->scc.tv.tuntype, ss->scc.tv.channel, ss->scc.tv.fine, ss->scc.tv.country, UNIT(dev)); #ifdef SOFT_INTR splx(s); #else enable_intr(); #endif /* SOFT_INTR */ return 0; } STATIC_CDEVSW int scc_close(dev_t dev, int flags, int fmt, struct proc *p) { struct scc_softc *ss=(struct scc_softc *)&scc_softc[UNIT(dev)]; if (ISCTL(dev)) return 0; if (!(ss->flags & SCC_ALIVE)) return ENXIO; ss->flags &= ~SCC_OPEN; ss->p = 0; ss->signal_num = 0; #if SCC_DEBUG > 0 printf("scc_close\n"); #endif return 0; } STATIC_CDEVSW int scc_write(dev_t dev, struct uio *uio, int ioflag) { #if SCC_DEBUG > 0 printf("scc_write\n"); #endif return ENXIO; } #if defined(REMAP_MEM_WIN) /* remap memory window */ /* START from pcic.h pcic.c */ #define PCIC_INDEX_0 0x3E0 /* index reg, chips 0 and 1 */ #define PCIC_DATA_0 0x3E1 /* data register, chips 0 and 1 */ #define PCIC_INDEX_1 0x3E2 /* index reg, chips 1 and 2 */ #define PCIC_DATA_1 0x3E3 /* data register, chips 1 and 2 */ #define INDEX(slot) ((slot) < 4 ? PCIC_INDEX_0 : PCIC_INDEX_1) #define DATA_(slot) ((slot) < 4 ? PCIC_DATA_0 : PCIC_DATA_1) #define OFFSET(slot) ((slot) % 4 * 0x40) #define MEM_START_ADDR(window) (((window) * 0x08) + 0x10) #define MEM_STOP_ADDR(window) (((window) * 0x08) + 0x12) #define MEM_OFFSET(window) (((window) * 0x08) + 0x14) #define MEM_ENABLE_BIT(window) ((1) << (window)) #define IO_STOP_ADDR(window) ((window) ? PCIC_IO1_SPL : PCIC_IO0_SPL) #define IO_ENABLE_BIT(window) ((window) ? PCIC_IO1_EN : PCIC_IO0_EN) #define IO_CS16_BIT(window) ((window) ? PCIC_IO1_CS16 : PCIC_IO0_CS16) enum memtype { COMMON, ATTRIBUTE }; static inline unsigned char pcic_getb (int slot, int reg); void pcic_putb (int slot, int reg, unsigned char val); static inline unsigned short pcic_getw (int slot, int reg); static inline void pcic_putw (int slot, int reg, unsigned short val); void pcic_map_memory (int slot, int window, unsigned long sys_addr, unsigned long card_addr, unsigned long length, enum memtype type, int width); void pcic_unmap_memory (int slot, int window); static inline unsigned char pcic_getb (int slot, int reg) { outb (INDEX(slot), OFFSET (slot) + reg); return inb (DATA_(slot)); } void pcic_putb (int slot, int reg, unsigned char val) { outb (INDEX(slot), OFFSET (slot) + reg); outb (DATA_(slot), val); } static inline unsigned short pcic_getw (int slot, int reg) { return pcic_getb (slot, reg) | (pcic_getb (slot, reg+1) << 8); } static inline void pcic_putw (int slot, int reg, unsigned short val) { pcic_putb (slot, reg, val & 0xff); pcic_putb (slot, reg + 1, (val >> 8) & 0xff); } void pcic_map_memory (int slot, int window, unsigned long sys_addr, unsigned long card_addr, unsigned long length, enum memtype type, int width) { unsigned short offset; unsigned short mem_start_addr; unsigned short mem_stop_addr; sys_addr >>= 12; card_addr >>= 12; length >>= 12; /* * compute an offset for the chip such that * (sys_addr + offset) = card_addr * but the arithmetic is done modulo 2^14 */ offset = (card_addr - sys_addr) & 0x3FFF; /* * now OR in the bit for "attribute memory" if necessary */ if (type == ATTRIBUTE) { offset |= (PCIC_REG << 8); /* REG == "region active" pin on card */ } /* * okay, set up the chip memory mapping registers, and turn * on the enable bit for this window. * if we are doing 16-bit wide accesses (width == 2), * turn on the appropriate bit. * * XXX for now, we set all of the wait state bits to zero. * Not really sure how they should be set. */ mem_start_addr = sys_addr & 0xFFF; if (width == 2) mem_start_addr |= (PCIC_DATA16 << 8); mem_stop_addr = (sys_addr + length) & 0xFFF; pcic_putw (slot, MEM_START_ADDR(window), mem_start_addr); pcic_putw (slot, MEM_STOP_ADDR(window), mem_stop_addr); pcic_putw (slot, MEM_OFFSET(window), offset); /* * Assert the bit (PCIC_MEMCS16) that says to decode all of * the address lines. */ pcic_putb (slot, PCIC_ADDRWINE, pcic_getb (slot, PCIC_ADDRWINE) | MEM_ENABLE_BIT(window) | PCIC_MEMCS16); } void pcic_unmap_memory (int slot, int window) { /* * seems like we need to turn off the enable bit first, after which * we can clear the registers out just to be sure. */ pcic_putb (slot, PCIC_ADDRWINE, pcic_getb (slot, PCIC_ADDRWINE) & ~MEM_ENABLE_BIT(window)); pcic_putw (slot, MEM_START_ADDR(window), 0); pcic_putw (slot, MEM_STOP_ADDR(window), 0); pcic_putw (slot, MEM_OFFSET(window), 0); } /* END from pcic.h pcic.c */ #endif /* defined(REMAP_MEM_WIN) */ STATIC_CDEVSW int scc_read(dev_t dev, struct uio *uio, int ioflag) { struct scc_softc *ss=(struct scc_softc *)&scc_softc[UNIT(dev)]; long times, page, count, offset, vsync, vsync_offset; long uio_resid, uio_offset; int status=0; int i; #ifdef PCCARD_MEM struct slot *slt; struct mem_desc *mp; int win = 0; #endif /* PCCARD_MEM */ #ifdef SOFT_INTR int s; #endif /* SOFT_INTR */ if (ss->gone) return ENODEV; if ((ss->flags & SCC_ALIVE)==0) return ENXIO; if (ISCTL(dev)) return ENXIO; if ((ss->flags & SCC_OPEN)==0) return EBUSY; if (ss->scc.spdmode == SCC_SLOW) FreezeVPX(0, UNIT(dev)); #ifdef PCCARD_MEM slt = dev_tab[UNIT(dev)]->slt; if (slt == NULL || slt->state != filled) return(ENXIO); #if 0 if (win < 0 || win >= slt->ctrl->maxmem) return(EINVAL); #endif mp = &slt->mem[win]; #endif /* PCCARD_MEM */ uio_resid = uio->uio_resid; uio_offset = uio->uio_offset; vsync = ss->scc.geomet.width * 2 * 6; /* ad hoc */ times = (uio_resid + vsync) / ss->msize; if (times * ss->msize < uio_resid + vsync) ++times; for (i=0; imsize; offset = vsync_offset % ss->msize; count = min(uio_resid, ss->msize - offset); if (ss->gone) return ENODEV; #ifdef SOFT_INTR s = splbio(); #else disable_intr(); #endif #if defined(REMAP_MEM_WIN) /* remap memory window */ pcic_unmap_memory(ss->slot, 0); pcic_map_memory(ss->slot, 0, kvtop(ss->maddr), page * ss->msize, ss->msize, COMMON, 1); #if SCC_DEBUG > 1 printf("scc_read maddr=%x, offset=%x, count=%x\n", kvtop(ss->maddr), offset, count); #endif #endif /* defined(REMAP_MEM_WIN) */ #ifdef PCCARD_MEM /* unmap memory */ mp->flags = 0; slt->ctrl->mapmem(slt, win); /* map memory */ mp->flags = MDF_ACTIVE; mp->card = page * ss->msize; mp->size = ss->msize + 0x1000; mp->start = kvtop(ss->maddr); slt->ctrl->mapmem(slt, win); #endif /* PCCARD_MEM */ status = uiomove(ss->maddr + offset, count, uio); #ifdef SOFT_INTR splx(s); #else enable_intr(); #endif /* SOFT_INTR */ uio_resid -= count; uio_offset += count; #if SCC_DEBUG > 1 printf("uio->uio_offset=%lx ", uio->uio_offset); printf("uio->uio_resid=%lx\n", uio->uio_resid); printf(" uio_offset=%lx ", uio_offset); printf(" uio_resid=%lx\n", uio_resid); #endif /* SCC_DEBUG > 1 */ #ifdef BUGGY_UIO uio->uio_resid = uio_resid; uio->uio_offset = uio_offset; #endif /* BUGGY_UIO */ } if (ss->scc.spdmode == SCC_SLOW) FreezeVPX(1, UNIT(dev)); if (uio->uio_resid > 0) return (ENOSPC); else return (status); } STATIC_CDEVSW int scc_ioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) { struct scc_softc *ss=(struct scc_softc *)&scc_softc[UNIT(dev)]; scc_geomet_t *geomet; scc_tv_t *tv; scc_color_t *color; int *inttmp; if (ss->gone) return (ENODEV); if (!data) return(EINVAL); if (ISCTL(dev)) printf("ioctl by sccctl\n"); switch(cmd){ case SCCSETMODE: inttmp = (int *)data; if ((*inttmp != SCC_PAL) && (*inttmp != SCC_NTSC)) return (EINVAL); ss->scc.mode = *inttmp; InitVPX(ss->iobase, ss->scc.mode, 0, ss->scc.geomet.width, ss->scc.geomet.height, 1, ss->scc.format, UNIT(dev)); break; case SCCGETMODE: inttmp = (int *)data; *inttmp = ss->scc.mode; break; case SCCSETGEO: geomet = (struct scc_geomet *)data; if (ss->scc.mode == SCC_PAL) { if (geomet->width <= 0 || geomet->width > SCC_PALWIDTH || geomet->height <= 0 || geomet->height > SCC_PALHEIGHT) return (EINVAL); } else { /* SCC_NTSC */ if (geomet->width <= 0 || geomet->width > SCC_NTSCWIDTH || geomet->height <= 0 || geomet->height > SCC_NTSCHEIGHT) return (EINVAL); } ss->scc.geomet = *geomet; SetVPXRect(ss->scc.geomet.width, ss->scc.geomet.height, UNIT(dev)); break; case SCCGETGEO: geomet = (struct scc_geomet *)data; *geomet = ss->scc.geomet; break; case SCCSETFMT: inttmp = (int *)data; if (*inttmp < SCC_YUV422 || *inttmp > SCC_RGB555) return (EINVAL); ss->scc.format = *inttmp; InitVPX(ss->iobase, ss->scc.mode, 0, ss->scc.geomet.width, ss->scc.geomet.height, 1, ss->scc.format, UNIT(dev)); break; case SCCGETFMT: inttmp = (int *)data; *inttmp = ss->scc.format; break; case SCCSETSPDMODE: inttmp = (int *)data; if (*inttmp != SCC_SLOW && *inttmp != SCC_FAST) return (EINVAL); ss->scc.spdmode = *inttmp; break; case SCCGETSPDMODE: inttmp = (int *)data; *inttmp = ss->scc.spdmode; break; case SCCSETTVCHANNEL: tv = (struct scc_tv *)data; if (tv->country == 0) { /* Japan */ if (tv->channel < SCC_MINCHANNELJP || tv->channel > SCC_MAXCHANNELJP) return (EINVAL); } else { /* USA */ if (tv->channel < SCC_MINCHANNELUS || tv->channel > SCC_MAXCHANNELUS) return (EINVAL); } ss->scc.tv = *tv; SetTVChannel(ss->scc.tv.tuntype, ss->scc.tv.channel, ss->scc.tv.fine, ss->scc.tv.country, UNIT(dev)); break; case SCCGETTVCHANNEL: tv = (struct scc_tv *)data; *tv = ss->scc.tv; break; case SCCSETCOLOR: color = (struct scc_color *)data; if (color->brightness < 0 || color->brightness > SCC_MAXBRIGHTNESS || color->contrast < 0 || color->contrast > SCC_MAXCONTRAST || color->saturation < 0 || color->saturation > SCC_MAXSATURATION || color->hue < 0 || color->hue > SCC_MAXHUE) return (EINVAL); ss->scc.color = *color; SetVPXColor(ss->scc.color.brightness, ss->scc.color.contrast, ss->scc.color.saturation, ss->scc.color.hue, UNIT(dev)); break; case SCCGETCOLOR: color = (struct scc_color *)data; *color = ss->scc.color; break; default: return ENOTTY; } return 0; } STATIC_CDEVSW int scc_select(dev_t dev, int rw, struct proc *p) { return ENXIO; } /* * Interrupt procedure. * Just call a user level interrupt routine. */ void sccintr(int unit) { struct scc_softc *ss=(struct scc_softc *)&scc_softc[unit]; if (ss->gone) return; if (ss->p && ss->signal_num) psignal(ss->p, ss->signal_num); } STATIC_CDEVSW int scc_mmap(dev_t dev, int offset, int nprot) { struct scc_softc *ss=(struct scc_softc *)&scc_softc[UNIT(dev)]; #ifdef PCCARD_MEM struct slot *slt; struct mem_desc *mp; int win = 0; #endif /* PCCARD_MEM */ if (ss->gone) return ENODEV; if ((ss->flags & SCC_ALIVE)==0) return ENXIO; if (ISCTL(dev)) return ENXIO; if ((ss->flags & SCC_OPEN)==0) return EBUSY; if (offset != 0) { printf("scc mmap failed, offset = 0x%x != 0x0\n", offset); return -1; } #if defined(REMAP_MEM_WIN) /* remap memory window */ pcic_unmap_memory(ss->slot, 0); pcic_map_memory(ss->slot, 0, kvtop(ss->maddr), 0, ss->msize, COMMON, 1); #if SCCDEBUG > 1 printf("scc_mmap maddr=%x, offset=%x, count=%x\n", kvtop(ss->maddr), offset, count); #endif #endif /* defined(REMAP_MEM_WIN) */ #ifdef PCCARD_MEM slt = dev_tab[UNIT(dev)]->slt; if (slt == NULL || slt->state != filled) return(ENXIO); mp = &slt->mem[win]; /* unmap memory */ mp->flags = 0; slt->ctrl->mapmem(slt, win); /* map memory */ mp->flags = MDF_ACTIVE; mp->card = 0; mp->size = ss->msize + 0x1000; mp->start = kvtop(ss->maddr); slt->ctrl->mapmem(slt, win); #endif /* PCCARD_MEM */ if ((nprot & PROT_EXEC) || (nprot & PROT_WRITE)) return -1; return i386_btop(ss->maddr); } #ifndef FREEBSD215R static void scc_drvinit(void *unused) { static scc_devsw_installed = 0; dev_t dev; if (!scc_devsw_installed) { dev = makedev(CDEV_MAJOR, scc_devsw_installed); cdevsw_add(&dev, &scc_cdevsw, NULL); ++scc_devsw_installed; } } SYSINIT(sccdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,scc_drvinit,NULL) #endif /* FREEBSD215R */ #ifdef ACTUALLY_LKM_NOT_KERNEL MOD_DEV(scc, LM_DT_CHAR, CDEV_MAJOR, &scc_cdevsw); static int scc_load(struct lkm_table *lkmtp, int cmd) { pccard_add_driver(&scc_info); scc_drvinit(NULL); return 0; } static int scc_unload(struct lkm_table *lkmtp, int cmd) { pccard_remove_driver(&scc_info); return 0; } static int scc_stat(struct lkm_table *lkmtp, int cmd) { return 0; } int scc_mod(struct lkm_table *lkmtp, int cmd, int var) { #define _module scc_module DISPATCH(lkmtp, cmd, var, scc_load, scc_unload, scc_stat); } #endif /* ACTUALLY_LKM_NOT_KERNEL */ #endif /* NSCC */