970b6faae9
#define COMPAT_PCI_DRIVER(name,data) DATA_SET(pcidevice_set,data) .. to 2.2.x and 3.x if people think it's worth it. Driver writers can do this if it's not defined. (The reason for this is that I'm trying to progressively eliminate use of linker_sets where it hurts modularity and runtime load capability, and these DATA_SET's keep getting in the way.)
2098 lines
61 KiB
C
2098 lines
61 KiB
C
/*
|
|
* Copyright (c) 1995 Mark Tinguely and Jim Lowe
|
|
* 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 Mark Tinguely and Jim Lowe
|
|
* 4. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
|
|
*/
|
|
|
|
/* Change History:
|
|
8/21/95 Release
|
|
8/23/95 On advice from Stefan Esser, added volatile to PCI
|
|
memory pointers to remove PCI caching .
|
|
8/29/95 Fixes suggested by Bruce Evans.
|
|
meteor_mmap should return -1 on error rather than 0.
|
|
unit # > NMETEOR should be unit # >= NMETEOR.
|
|
10/24/95 Turn 50 Hz processing for SECAM and 60 Hz processing
|
|
off for AUTOMODE.
|
|
11/11/95 Change UV from always begin signed to ioctl selected
|
|
to either signed or unsigned.
|
|
12/07/95 Changed 7196 startup codes for 50 Hz as recommended
|
|
by Luigi Rizzo (luigi@iet.unipi.it)
|
|
12/08/95 Clear SECAM bit in PAL/NTSC and set input field count
|
|
bits for 50 Hz mode (PAL/SECAM) before I was setting the
|
|
output count bits. by Luigi Rizzo (luigi@iet.unipi.it)
|
|
12/18/95 Correct odd DMA field (never exceed, but good for safety
|
|
Changed 7196 startup codes for 50 Hz as recommended
|
|
by Luigi Rizzo (luigi@iet.unipi.it)
|
|
12/19/95 Changed field toggle mode to enable (offset 0x3c)
|
|
recommended by luigi@iet.unipi.it
|
|
Added in prototyping, include file, staticizing,
|
|
and DEVFS changes from FreeBSD team.
|
|
Changed the default allocated pages from 151 (NTSC)
|
|
to 217 (PAL).
|
|
Cleaned up some old comments in iic_write().
|
|
Added a Field (even or odd) only capture mode to
|
|
eliminate the high frequency problems with compression
|
|
algorithms. Recommended by luigi@iet.unipi.it.
|
|
Changed geometry ioctl so if it couldn't allocated a
|
|
large enough contiguous space, it wouldn't free the
|
|
stuff it already had.
|
|
Added new mode called YUV_422 which delivers the
|
|
data in planer Y followed by U followed by V. This
|
|
differs from the standard YUV_PACKED mode in that
|
|
the chrominance (UV) data is in the correct (different)
|
|
order. This is for programs like vic and mpeg_encode
|
|
so they don't have to reorder the chrominance data.
|
|
Added field count to stats.
|
|
Increment frame count stat if capturing continuous on
|
|
even frame grabs.
|
|
Added my email address to these comments
|
|
(james@cs.uwm.edu) suggested by (luigi@iet.unipt.it :-).
|
|
Changed the user mode signal mechanism to allow the
|
|
user program to be interrupted at the end of a frame
|
|
in any one of the modes. Added SSIGNAL ioctl.
|
|
Added a SFPS/GFPS ioctl so one may set the frames per
|
|
second that the card catpures. This code needs to be
|
|
completed.
|
|
Changed the interrupt routine so synchronous capture
|
|
will work on fields or frames and the starting frame
|
|
can be either even or odd.
|
|
Added HALT_N_FRAMES and CONT_N_FRAMES so one could
|
|
stop and continue synchronous capture mode.
|
|
Change the tsleep/wakeup function to wait on mtr
|
|
rather than &read_intr_wait.
|
|
1/22/96 Add option (METEOR_FreeBSD_210) for FreeBSD 2.1
|
|
to compile.
|
|
Changed intr so it only printed errors every 50 times.
|
|
Added unit number to error messages.
|
|
Added get_meteor_mem and enabled range checking.
|
|
1/30/96 Added prelim test stuff for direct video dma transfers
|
|
from Amancio Hasty (hasty@rah.star-gate.com). Until
|
|
we get some stuff sorted out, this will be ifdef'ed
|
|
with METEOR_DIRECT_VIDEO. This is very dangerous to
|
|
use at present since we don't check the address that
|
|
is passed by the user!!!!!
|
|
2/26/96 Added special SVIDEO input device type.
|
|
2/27/96 Added meteor_reg.h file and associate types Converted
|
|
meteor.c over to using meteor.h file. Prompted by
|
|
Lars Jonas Olsson <ljo@po.cwru.edu>.
|
|
2/28/96 Added meteor RGB code from Lars Jonas Olsson
|
|
<ljo@po.cwru.edu>. I make some mods to this code, so
|
|
I hope it still works as I don't have an rgb card to
|
|
test with.
|
|
2/29/96 <ljo@po.cwru.edu> tested the meteor RGB and supplied
|
|
me with diffs. Thanks, we now have a working RGB
|
|
version of the driver. Still need to clean up this
|
|
code.
|
|
3/1/96 Fixed a nasty little bug that was clearing the VTR
|
|
mode bit when the 7196 status was requested.
|
|
3/15/96 Fixed bug introduced in previous version that
|
|
stopped the only fields mode from working.
|
|
Added METEOR{GS}TS ioctl, still needs work.
|
|
3/25/96 Added YUV_9 and YUV_12 modes. Cleaned up some of the
|
|
code and converted variables to use the new register
|
|
types.
|
|
4/8/96 Fixed the a bug in with the range enable. Pointed
|
|
out by Jim Bray.
|
|
5/13/96 Fix the FPS ioctl so it actually sets the frames
|
|
per second. Code supplied by ian@robots.ox.ac.uk.
|
|
The new code implements a new define:
|
|
METEOR_SYSTEM_DEFAULT which should be defined as
|
|
METEOR_PAL, METEOR_SECAM, or METEOR_NTSC in your system
|
|
configuration file. If METEOR_SYSTEM_DEFAULT isn't
|
|
defined, and there is not a signal when set_fps is
|
|
called, then the call has no effect.
|
|
Changed the spelling of PLANER to PLANAR as pointed
|
|
out by Paco Hope <paco@cs.virigina.edu> and define
|
|
PLANER to be PLANAR for backward compatibility.
|
|
5/28/95 METEOR_INPUT_DEV_RCA -> METEOR_INPUT_DEV0, not
|
|
METEOR_GEO_DEV0. Pointed out by Ian Reid,
|
|
<ian@robots.ox.ac.uk>.
|
|
METEOR_DEV_MASK should be 0x0000f000 and not
|
|
0x2000f000, otherwise METEOR_RGB gets masked
|
|
out. Pointed out by Ian Reid.
|
|
Changed the fps code to give even distribution for
|
|
low frame rates. Code supplied by Ian Reid.
|
|
Fix some problems with the RGB version. Patch supplied
|
|
by <ljo@po.cwru.edu>.
|
|
Added METEOR_FIELD_MODE to include files for a
|
|
future version of this driver.
|
|
*/
|
|
|
|
#include "meteor.h"
|
|
|
|
#if NMETEOR > 0
|
|
#include "opt_devfs.h"
|
|
#include "opt_meteor.h"
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/conf.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/signalvar.h>
|
|
#include <sys/mman.h>
|
|
#ifdef DEVFS
|
|
#include <sys/devfsext.h>
|
|
#endif /* DEVFS */
|
|
#include <sys/uio.h>
|
|
|
|
#if defined(METEOR_FreeBSD_210)
|
|
#include <machine/cpu.h> /* bootverbose */
|
|
#endif
|
|
|
|
#include <vm/vm.h>
|
|
#include <vm/vm_kern.h>
|
|
#include <vm/pmap.h>
|
|
#include <vm/vm_extern.h>
|
|
|
|
#include "pci.h"
|
|
#if NPCI > 0
|
|
#include <pci/pcivar.h>
|
|
#include <pci/pcireg.h>
|
|
#endif
|
|
#include <machine/ioctl_meteor.h>
|
|
#include <pci/meteor_reg.h>
|
|
|
|
|
|
static void meteor_intr __P((void *arg));
|
|
|
|
/*
|
|
* Allocate enough memory for:
|
|
* 768x576 RGB 16 or YUV (16 storage bits/pixel) = 884736 = 216 pages
|
|
*
|
|
* You may override this using the options "METEOR_ALLOC_PAGES=value" in your
|
|
* kernel configuration file.
|
|
*/
|
|
#ifndef METEOR_ALLOC_PAGES
|
|
#define METEOR_ALLOC_PAGES 217
|
|
#endif
|
|
#define METEOR_ALLOC (METEOR_ALLOC_PAGES * PAGE_SIZE)
|
|
|
|
static meteor_reg_t meteor[NMETEOR];
|
|
#define METEOR_NUM(mtr) ((mtr - &meteor[0])/sizeof(meteor_reg_t))
|
|
|
|
#define METPRI (PZERO+8)|PCATCH
|
|
|
|
static const char* met_probe (pcici_t tag, pcidi_t type);
|
|
static void met_attach(pcici_t tag, int unit);
|
|
static u_long met_count;
|
|
|
|
static struct pci_device met_device = {
|
|
"meteor",
|
|
met_probe,
|
|
met_attach,
|
|
&met_count
|
|
};
|
|
|
|
COMPAT_PCI_DRIVER (meteor, met_device);
|
|
|
|
#if defined(METEOR_FreeBSD_210) /* XXX */
|
|
d_open_t meteor_open;
|
|
d_close_t meteor_close;
|
|
d_read_t meteor_read;
|
|
d_write_t meteor_write;
|
|
d_ioctl_t meteor_ioctl;
|
|
d_mmap_t meteor_mmap;
|
|
#else
|
|
static d_open_t meteor_open;
|
|
static d_close_t meteor_close;
|
|
static d_read_t meteor_read;
|
|
static d_write_t meteor_write;
|
|
static d_ioctl_t meteor_ioctl;
|
|
static d_mmap_t meteor_mmap;
|
|
|
|
#define CDEV_MAJOR 67
|
|
static struct cdevsw meteor_cdevsw =
|
|
{ meteor_open, meteor_close, meteor_read, meteor_write, /*67*/
|
|
meteor_ioctl, nostop, nullreset, nodevtotty,/* Meteor */
|
|
seltrue, meteor_mmap, NULL, "meteor", NULL, -1 };
|
|
#endif
|
|
|
|
static mreg_t saa7116_pci_default[sizeof(struct saa7116_regs)/sizeof(mreg_t)]={
|
|
/* PCI Memory registers */
|
|
/* BITS Type Description */
|
|
/* 0x00 */ 0x00000000, /* 31:1 e*RW DMA 1 (Even)
|
|
0 RO 0x0 */
|
|
/* 0x04 */ 0x00000000, /* 31:2 e*RW DMA 2 (Even)
|
|
1:0 RO 0x0 */
|
|
/* 0x08 */ 0x00000000, /* 31:2 e*RW DMA 3 (Even)
|
|
1:0 RO 0x0 */
|
|
/* 0x0c */ 0x00000000, /* 31:1 o*RW DMA 1 (Odd)
|
|
0 RO 0x0 */
|
|
/* 0x10 */ 0x00000000, /* 31:2 o*RW DMA 2 (Odd)
|
|
1:0 RO 0x0 */
|
|
/* 0x14 */ 0x00000000, /* 31:2 o*RW DMA 3 (Odd)
|
|
1:0 RO 0x0 */
|
|
/* 0x18 */ 0x00000500, /* 15:2 e*RW Stride 1 (Even)
|
|
1:0 RO 0x0 */
|
|
/* 0x1c */ 0x00000000, /* 15:2 e*RW Stride 2 (Even)
|
|
1:0 RO 0x0 */
|
|
/* 0x20 */ 0x00000000, /* 15:2 e*RW Stride 3 (Even)
|
|
1:0 RO 0x0 */
|
|
/* 0x24 */ 0x00000500, /* 15:2 o*RW Stride 1 (Odd)
|
|
1:0 RO 0x0 */
|
|
/* 0x28 */ 0x00000000, /* 15:2 o*RW Stride 2 (Odd)
|
|
1:0 RO 0x0 */
|
|
/* 0x2c */ 0x00000000, /* 15:2 o*RW Stride 3 (Odd)
|
|
1:0 RO 0x0 */
|
|
/* 0x30 */ 0xeeeeee01, /* 31:8 *RW Route (Even)
|
|
7:0 *RW Mode (Even) */
|
|
/* 0x34 */ 0xeeeeee01, /* 31:8 *RW Route (Odd)
|
|
7:0 *RW Mode (Odd) */
|
|
/* 0x38 */ 0x00200020, /* 22:16 *RW FIFO Trigger Planer Mode,
|
|
6:0 *RW FIFO Trigger Packed Mode */
|
|
/* 0x3c */ 0x00000107, /* 9:8 *RW Reserved (0x0)
|
|
2 *RW Field Toggle
|
|
1 *RW Reserved (0x1)
|
|
0 *RW Reserved (0x1) */
|
|
/* 0x40 */ 0x000000c0, /* 15 *RW Range Enable
|
|
14 *RW Corrupt Disable
|
|
11 *RR Address Error (Odd)
|
|
10 *RR Address Error (Even)
|
|
9 *RR Field Corrupt (Odd)
|
|
8 *RR Field Corrupt (Even)
|
|
7 *RW Fifo Enable
|
|
6 *RW VRSTN#
|
|
5 *RR Field Done (Odd)
|
|
4 *RR Field Done (Even)
|
|
3 *RS Single Field Capture (Odd)
|
|
2 *RS Single Field Capture (Even)
|
|
1 *RW Capture (ODD) Continous
|
|
0 *RW Capture (Even) Continous */
|
|
/* 0x44 */ 0x00000000, /* 7:0 *RW Retry Wait Counter */
|
|
/* 0x48 */ 0x00000307, /* 10 *RW Interrupt mask, start of field
|
|
9 *RW Interrupt mask, end odd field
|
|
8 *RW Interrupt mask, end even field
|
|
2 *RR Interrupt status, start of field
|
|
1 *RR Interrupt status, end of odd
|
|
0 *RR Interrupt status, end of even */
|
|
/* 0x4c */ 0x00000001, /* 31:0 *RW Field Mask (Even) continous */
|
|
/* 0x50 */ 0x00000001, /* 31:0 *RW Field Mask (Odd) continous */
|
|
/* 0x54 */ 0x00000000, /* 20:16 *RW Mask Length (Odd)
|
|
4:0 *RW Mask Length (Even) */
|
|
/* 0x58 */ 0x0005007c, /* 22:16 *RW FIFO almost empty
|
|
6:0 *RW FIFO almost full */
|
|
/* 0x5c */ 0x461e1e0f, /* 31:24 *RW I2C Phase 4
|
|
23:16 *RW I2C Phase 3
|
|
15:8 *RW I2C Phase 2
|
|
7:0 *RW I2C Phase 1 */
|
|
/* 0x60 */ 0x00000300, /* 31:24 *RO I2C Read Data
|
|
23:16 **RW I2C Auto Address
|
|
11 RO I2C SCL Input
|
|
10 RO I2C SDA Input
|
|
9 RR I2C Direct Abort
|
|
8 RR I2C Auto Abort
|
|
3 RW I2C SCL Output
|
|
2 RW I2C SDA Output
|
|
1 RW I2C Bypass
|
|
0 RW I2C Auto Enable */
|
|
/* 0x64 */ 0x00000000, /* 24 RS I2C New Cycle
|
|
23:16 **RW I2C Direct Address
|
|
15:8 **RW I2C Direct Sub-address
|
|
7:0 **RW I2C Direct Write Address */
|
|
/* 0x68 */ 0x00000000, /* 31:24 **RW I2C Auto Sub-address 1 (Even)
|
|
23:16 **RW I2C Auto Data 1 (Even)
|
|
15:8 **RW I2C Auto Sub-address 0 (Even)
|
|
7:0 **RW I2C Auto Data 0 (Even) */
|
|
/* 0x6c */ 0x00000000, /* 31:24 **RW I2C Auto Sub-address 3 (Even)
|
|
23:16 **RW I2C Auto Data 3 (Even)
|
|
15:8 **RW I2C Auto Sub-address 2 (Even)
|
|
7:0 **RW I2C Auto Data 2 (Even) */
|
|
/* 0x70 */ 0x00000000, /* 31:24 **RW I2C Auto Sub-address 5 (Even)
|
|
23:16 **RW I2C Auto Data 5 (Even)
|
|
15:8 **RW I2C Auto Sub-address 4 (Even)
|
|
7:0 **RW I2C Auto Data 4 (Even) */
|
|
/* 0x74 */ 0x00000000, /* 31:24 **RW I2C Auto Sub-address 7 (Even)
|
|
23:16 **RW I2C Auto Data 7 (Even)
|
|
15:8 **RW I2C Auto Sub-address 6 (Even)
|
|
7:0 **RW I2C Auto Data 6 (Even) */
|
|
/* 0x78 */ 0x00000000, /* 31:24 **RW I2C Auto Sub-address 1 (Odd)
|
|
23:16 **RW I2C Auto Data 1 (Odd)
|
|
15:8 **RW I2C Auto Sub-address 0 (Odd)
|
|
7:0 **RW I2C Auto Data 0 (Odd) */
|
|
/* 0x7c */ 0x00000000, /* 31:24 **RW I2C Auto Sub-address 3 (Odd)
|
|
23:16 **RW I2C Auto Data 3 (Odd)
|
|
15:8 **RW I2C Auto Sub-address 2 (Odd)
|
|
7:0 **RW I2C Auto Data 2 (Odd) */
|
|
/* 0x80 */ 0x00000000, /* 31:24 **RW I2C Auto Sub-address 5 (Odd)
|
|
23:16 **RW I2C Auto Data 5 (Odd)
|
|
15:8 **RW I2C Auto Sub-address 4 (Odd)
|
|
7:0 **RW I2C Auto Data 4 (Odd) */
|
|
/* 0x84 */ 0x00000000, /* 31:24 **RW I2C Auto Sub-address 7 (Odd)
|
|
23:16 **RW I2C Auto Data 7 (Odd)
|
|
15:8 **RW I2C Auto Sub-address 6 (Odd)
|
|
7:0 **RW I2C Auto Data 6 (Odd) */
|
|
/* 0x88 */ 0x00000000, /* 23:16 **RW I2C Register Enable (Odd)
|
|
7:0 **RW I2C Register Enable (Even) */
|
|
/* 0x8c */ 0x00000000, /* 23:2 e*RW DMA End (Even)
|
|
1:0 RO 0x0 */
|
|
/* 0x90 */ 0x00000000 /* 23:2 e*RW DMA End (Odd)
|
|
1:0 RO 0x0 */
|
|
};
|
|
|
|
static u_char saa7196_i2c_default[NUM_SAA7196_I2C_REGS] = {
|
|
/* SAA7196 I2C bus control */
|
|
/* BITS Function */
|
|
/* 00 */ 0x50, /* 7:0 Increment Delay */
|
|
/* 01 */ 0x30, /* 7:0 Horizontal Sync Begin for 50hz */
|
|
/* 02 */ 0x00, /* 7:0 Horizontal Sync Stop for 50hz */
|
|
/* 03 */ 0xe8, /* 7:0 Horizontal Sync Clamp Start for 50hz */
|
|
/* 04 */ 0xb6, /* 7:0 Horizontal Sync Clamp Stop for 50hz */
|
|
/* 05 */ 0xf4, /* 7:0 Horizontal Sync Start after PH1 for 50hz */
|
|
/* 06 */ 0x46, /* 7 Input mode =0 CVBS, =1 S-Video
|
|
6 Pre filter
|
|
5:4 Aperture Bandpass characteristics
|
|
3:2 Coring range for high freq
|
|
1:0 Aperture bandpass filter weights */
|
|
/* 07 */ 0x00, /* 7:0 Hue */
|
|
/* 08 */ 0x7f, /* 7:3 Colour-killer threshold QAM (PAL, NTSC) */
|
|
/* 09 */ 0x7f, /* 7:3 Colour-killer threshold SECAM */
|
|
/* 0a */ 0x7f, /* 7:0 PAL switch sensitivity */
|
|
/* 0b */ 0x7f, /* 7:0 SECAM switch sensitivity */
|
|
/* 0c */ 0x40, /* 7 Colour-on bit
|
|
6:5 AGC filter */
|
|
/* 0d */ 0x84, /* 7 VTR/TV mode bit = 1->VTR mode
|
|
3 Realtime output mode select bit
|
|
2 HREF position select
|
|
1 Status byte select
|
|
0 SECAM mode bit */
|
|
/* 0e */ 0x38, /* 7 Horizontal clock PLL
|
|
5 Select interal/external clock source
|
|
4 Output enable of Horizontal/Vertical sync
|
|
3 Data output YUV enable
|
|
2 S-VHS bit
|
|
1 GPSW2
|
|
0 GPSW1 */
|
|
/* 0f */ 0x50, /* 7 Automatic Field detection
|
|
6 Field Select 0 = 50hz, 1=60hz
|
|
5 SECAM cross-colour reduction
|
|
4 Enable sync and clamping pulse
|
|
3:1 Luminance delay compensation */
|
|
/* 10 */ 0x00, /* 2 Select HREF Position
|
|
1:0 Vertical noise reduction */
|
|
/* 11 */ 0x2c, /* 7:0 Chrominance gain conrtol for QAM */
|
|
/* 12 */ 0x40, /* 7:0 Chrominance saturation control for VRAM port */
|
|
/* 13 */ 0x40, /* 7:0 Luminance contract control for VRAM port */
|
|
/* 14 */ 0x34, /* 7:0 Horizontal sync begin for 60hz */
|
|
#ifdef notdef
|
|
/* 15 */ 0x0c, /* 7:0 Horizontal sync stop for 60hz */
|
|
/* 16 */ 0xfb, /* 7:0 Horizontal clamp begin for 60hz */
|
|
/* 17 */ 0xd4, /* 7:0 Horizontal clamp stop for 60hz */
|
|
/* 18 */ 0xec, /* 7:0 Horizontal sync start after PH1 for 60hz */
|
|
#else
|
|
0x0a, 0xf4, 0xce, 0xf4,
|
|
#endif
|
|
/* 19 */ 0x80, /* 7:0 Luminance brightness control for VRAM port */
|
|
/* 1a */ 0x00,
|
|
/* 1b */ 0x00,
|
|
/* 1c */ 0x00,
|
|
/* 1d */ 0x00,
|
|
/* 1e */ 0x00,
|
|
/* 1f */ 0x00,
|
|
/* 20 */ 0x90, /* 7 ROM table bypass switch
|
|
6:5 Set output field mode
|
|
4 VRAM port outputs enable
|
|
3:2 First pixel position in VRO data
|
|
1:0 FIFO output register select */
|
|
/* 21 */ 0x80, /* 7:0 [7:0] Pixel number per line on output */
|
|
/* 22 */ 0x80, /* 7:0 [7:0] Pixel number per line on input */
|
|
/* 23 */ 0x03, /* 7:0 [7:0] Horizontal start position of scaling win*/
|
|
/* 24 */ 0x8a, /* 7:5 Horizontal decimation filter
|
|
4 [8] Horizontal start position of scaling win
|
|
3:2 [9:8] Pixel number per line on input
|
|
1:0 [9:8] Pixel number per line on output */
|
|
/* 25 */ 0xf0, /* 7:0 [7:0] Line number per output field */
|
|
/* 26 */ 0xf0, /* 7:0 [7:0] Line number per input field */
|
|
/* 27 */ 0x0f, /* 7:0 [7:0] Vertical start of scaling window */
|
|
/* 28 */ 0x80, /* 7 Adaptive filter switch
|
|
6:5 Vertical luminance data processing
|
|
4 [8] Vertical start of scaling window
|
|
3:2 [9:8] Line number per input field
|
|
1:0 [9:8] Line number per output field */
|
|
/* 29 */ 0x16, /* 7:0 [7:0] Vertical bypass start */
|
|
/* 2a */ 0x00, /* 7:0 [7:0] Vertical bypass count */
|
|
/* 2b */ 0x00, /* 4 [8] Vertical bypass start
|
|
2 [8] Vertical bypass count
|
|
0 Polarity, internally detected odd even flag */
|
|
/* 2c */ 0x80, /* 7:0 Set lower limit V for colour-keying */
|
|
/* 2d */ 0x7f, /* 7:0 Set upper limit V for colour-keying */
|
|
/* 2e */ 0x80, /* 7:0 Set lower limit U for colour-keying */
|
|
/* 2f */ 0x7f, /* 7:0 Set upper limit U for colour-keying */
|
|
/* 30 */ 0xbf /* 7 VRAM bus output format
|
|
6 Adaptive geometrical filter
|
|
5 Luminance limiting value
|
|
4 Monochrome and two's complement output data sel
|
|
3 Line quailifier flag
|
|
2 Pixel qualifier flag
|
|
1 Transparent data transfer
|
|
0 Extended formats enable bit */
|
|
};
|
|
|
|
static u_char bt254_default[NUM_BT254_REGS] = {
|
|
0x00, /* 24 bpp */
|
|
0xa0,
|
|
0xa0,
|
|
0xa0,
|
|
0x50,
|
|
0x50,
|
|
0x50,
|
|
} ;
|
|
|
|
/*
|
|
* i2c_write:
|
|
* Returns 0 Succesful completion.
|
|
* Returns 1 If transfer aborted or timeout occured.
|
|
*
|
|
*/
|
|
static int i2c_print_err = 1;
|
|
static int
|
|
i2c_write(meteor_reg_t * mtr, u_char slave, u_char rw, u_char reg, u_char data)
|
|
{
|
|
register unsigned long wait_counter = 0x0001ffff;
|
|
register mreg_t * iic_write_loc = &mtr->base->i2c_write;
|
|
register int err = 0;
|
|
|
|
|
|
/* Write the data the the i2c write register */
|
|
*iic_write_loc = SAA7116_IIC_NEW_CYCLE |
|
|
(((u_long)slave|(u_long)rw) << 16) |
|
|
((u_long)reg << 8) | (u_long)data;
|
|
|
|
/* Wait until the i2c cycle is compeleted */
|
|
while((*iic_write_loc & SAA7116_IIC_NEW_CYCLE)) {
|
|
if(!wait_counter) break;
|
|
wait_counter--;
|
|
}
|
|
|
|
/* 1ffff should be enough delay time for the i2c cycle to complete */
|
|
if(!wait_counter) {
|
|
if(i2c_print_err)
|
|
printf("meteor%d: %d i2c %s transfer timeout 0x%x",
|
|
METEOR_NUM(mtr), slave,
|
|
rw ? "read" : "write", *iic_write_loc);
|
|
|
|
err=1;
|
|
}
|
|
|
|
/* Check for error on direct write, clear if any */
|
|
if(mtr->base->i2c_read & SAA7116_IIC_DIRECT_TRANSFER_ABORTED){
|
|
mtr->base->i2c_read |= SAA7116_IIC_DIRECT_TRANSFER_ABORTED;
|
|
if(i2c_print_err)
|
|
printf("meteor%d: 0x%x i2c %s tranfer aborted",
|
|
METEOR_NUM(mtr), slave,
|
|
rw ? "read" : "write" );
|
|
err= 1;
|
|
}
|
|
|
|
if(err) {
|
|
if(i2c_print_err)
|
|
printf(" - reg=0x%x, value=0x%x.\n", reg, data);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
#undef i2c_print
|
|
|
|
static const char *
|
|
met_probe (pcici_t tag, pcidi_t type)
|
|
{
|
|
|
|
switch (type) {
|
|
case SAA7116_PHILIPS_ID: /* meteor */
|
|
return("Philips SAA 7116");
|
|
};
|
|
return ((char *)0);
|
|
}
|
|
|
|
/* interrupt handling routine
|
|
complete meteor_read() if using interrupts
|
|
*/
|
|
static void
|
|
meteor_intr(void *arg)
|
|
{
|
|
meteor_reg_t *mtr = (meteor_reg_t *) arg;
|
|
mreg_t *cap = &mtr->base->cap_cntl,
|
|
*base = &mtr->base->dma1e,
|
|
*stat = &mtr->base->irq_stat;
|
|
u_long status = *stat,
|
|
cap_err = *cap & 0x00000f00,
|
|
#ifdef METEOR_CHECK_PCI_BUS
|
|
pci_err = pci_conf_read(mtr->tag,
|
|
PCI_COMMAND_STATUS_REG),
|
|
#endif
|
|
next_base = (u_long)(vtophys(mtr->bigbuf));
|
|
|
|
/*
|
|
* Disable future interrupts if a capture mode is not selected.
|
|
* This can happen when we are in the process of closing or
|
|
* changing capture modes, otherwise it shouldn't happen.
|
|
*/
|
|
if(!(mtr->flags & METEOR_CAP_MASK)) {
|
|
*cap &= 0x8ff0; /* disable future interrupts */
|
|
}
|
|
#ifdef METEOR_CHECK_PCI_BUS
|
|
/*
|
|
* Check for pci bus errors.
|
|
*/
|
|
#define METEOR_MASTER_ABORT 0x20000000
|
|
#define METEOR_TARGET_ABORT 0x10000000
|
|
if(pci_err & METEOR_MASTER_ABORT) {
|
|
printf("meteor%d: intr: pci bus master dma abort: 0x%x 0x%x.\n",
|
|
METEOR_NUM(mtr), *base, *(base+3));
|
|
pci_conf_write(mtr->tag, PCI_COMMAND_STATUS_REG, pci_err);
|
|
}
|
|
if(pci_err & METEOR_TARGET_ABORT) {
|
|
printf("meteor%d: intr: pci bus target dma abort: 0x%x 0x%x.\n",
|
|
METEOR_NUM(mtr), *base, *(base+3));
|
|
pci_conf_write(mtr->tag, PCI_COMMAND_STATUS_REG, pci_err);
|
|
}
|
|
#endif
|
|
/*
|
|
* Check for errors.
|
|
*/
|
|
if (cap_err) {
|
|
if (cap_err & 0x300) {
|
|
if(mtr->fifo_errors % 50 == 0) {
|
|
printf("meteor%d: capture error", METEOR_NUM(mtr));
|
|
printf(": %s FIFO overflow.\n",
|
|
cap_err&0x0100? "even" : "odd");
|
|
}
|
|
mtr->fifo_errors++ ; /* increment fifo capture errors cnt */
|
|
}
|
|
if (cap_err & 0xc00) {
|
|
if(mtr->dma_errors % 50 == 0) {
|
|
printf("meteor%d: capture error", METEOR_NUM(mtr));
|
|
printf(": %s DMA address.\n",
|
|
cap_err&0x0400? "even" : "odd");
|
|
}
|
|
mtr->dma_errors++ ; /* increment DMA capture errors cnt */
|
|
}
|
|
}
|
|
*cap |= 0x0f30; /* clear error and field done */
|
|
|
|
/*
|
|
* In synchronous capture mode we need to know what the address
|
|
* offset for the next field/frame will be. next_base holds the
|
|
* value for the even dma buffers (for odd, one must add stride).
|
|
*/
|
|
if((mtr->flags & METEOR_SYNCAP) && !mtr->synch_wait &&
|
|
(mtr->current < mtr->frames)) { /* could be !=, but < is safer */
|
|
/* next_base is initialized to mtr->bigbuf */
|
|
next_base += mtr->frame_size * mtr->current;
|
|
if(mtr->flags & METEOR_WANT_TS)
|
|
next_base += sizeof(struct timeval) * mtr->current;
|
|
}
|
|
|
|
/*
|
|
* Count the field and clear the field flag.
|
|
*
|
|
* In single mode capture, clear the continuous capture mode.
|
|
*
|
|
* In synchronous capture mode, if we have room for another field,
|
|
* adjust DMA buffer pointers.
|
|
* When we are above the hi water mark (hiwat), mtr->synch_wait will
|
|
* be set and we will not bump the DMA buffer pointers. Thus, once
|
|
* we reach the hi water mark, the driver acts like a continuous mode
|
|
* capture on the mtr->current frame until we hit the low water
|
|
* mark (lowat). The user had the option of stopping or halting
|
|
* the capture if this is not the desired effect.
|
|
*/
|
|
if (status & 0x1) { /* even field */
|
|
mtr->even_fields_captured++;
|
|
mtr->flags &= ~METEOR_WANT_EVEN;
|
|
if((mtr->flags & METEOR_SYNCAP) && !mtr->synch_wait) {
|
|
*base = next_base;
|
|
/* XXX should add adjustments for YUV_422 & PLANAR */
|
|
}
|
|
/*
|
|
* If the user requested to be notified via signal,
|
|
* let them know the field is complete.
|
|
*/
|
|
if(mtr->proc && (mtr->signal & METEOR_SIG_MODE_MASK))
|
|
psignal(mtr->proc, mtr->signal&(~METEOR_SIG_MODE_MASK));
|
|
}
|
|
if (status & 0x2) { /* odd field */
|
|
mtr->odd_fields_captured++;
|
|
mtr->flags &= ~METEOR_WANT_ODD;
|
|
if((mtr->flags & METEOR_SYNCAP) && !mtr->synch_wait) {
|
|
*(base+3) = next_base + *(base+6);
|
|
/* XXX should add adjustments for YUV_422 & PLANAR */
|
|
}
|
|
/*
|
|
* If the user requested to be notified via signal,
|
|
* let them know the field is complete.
|
|
*/
|
|
if(mtr->proc && (mtr->signal & METEOR_SIG_MODE_MASK))
|
|
psignal(mtr->proc, mtr->signal&(~METEOR_SIG_MODE_MASK));
|
|
}
|
|
|
|
/*
|
|
* If we have a complete frame.
|
|
*/
|
|
if(!(mtr->flags & METEOR_WANT_MASK)) {
|
|
mtr->frames_captured++;
|
|
/*
|
|
* post the completion time.
|
|
*/
|
|
if(mtr->flags & METEOR_WANT_TS) {
|
|
struct timeval *ts;
|
|
|
|
if(mtr->alloc_pages * PAGE_SIZE <= (mtr->frame_size +
|
|
sizeof(struct timeval))) {
|
|
ts =(struct timeval *)mtr->bigbuf +
|
|
mtr->frame_size;
|
|
/* doesn't work in synch mode except for first frame */
|
|
/* XXX */
|
|
microtime(ts);
|
|
}
|
|
}
|
|
/*
|
|
* Wake up the user in single capture mode.
|
|
*/
|
|
if(mtr->flags & METEOR_SINGLE)
|
|
wakeup((caddr_t)mtr);
|
|
/*
|
|
* If the user requested to be notified via signal,
|
|
* let them know the frame is complete.
|
|
*/
|
|
if(mtr->proc && !(mtr->signal & METEOR_SIG_MODE_MASK))
|
|
psignal(mtr->proc, mtr->signal&(~METEOR_SIG_MODE_MASK));
|
|
/*
|
|
* Reset the want flags if in continuous or
|
|
* synchronous capture mode.
|
|
*/
|
|
if(mtr->flags & (METEOR_CONTIN|METEOR_SYNCAP)) {
|
|
switch(mtr->flags & METEOR_ONLY_FIELDS_MASK) {
|
|
case METEOR_ONLY_ODD_FIELDS:
|
|
mtr->flags |= METEOR_WANT_ODD;
|
|
break;
|
|
case METEOR_ONLY_EVEN_FIELDS:
|
|
mtr->flags |= METEOR_WANT_EVEN;
|
|
break;
|
|
default:
|
|
mtr->flags |= METEOR_WANT_MASK;
|
|
break;
|
|
}
|
|
}
|
|
/*
|
|
* Special handling for synchronous capture mode.
|
|
*/
|
|
if(mtr->flags & METEOR_SYNCAP) {
|
|
struct meteor_mem *mm = mtr->mem;
|
|
/*
|
|
* Mark the current frame as active. It is up to
|
|
* the user to clear this, but we will clear it
|
|
* for the user for the current frame being captured
|
|
* if we are within the water marks (see below).
|
|
*/
|
|
mm->active |= 1 << (mtr->current - 1);
|
|
|
|
/*
|
|
* Since the user can muck with these values, we need
|
|
* to check and see if they are sane. If they don't
|
|
* pass the sanity check, disable the capture mode.
|
|
* This is rather rude, but then so was the user.
|
|
*
|
|
* Do we really need all of this or should we just
|
|
* eliminate the possiblity of allowing the
|
|
* user to change hi and lo water marks while it
|
|
* is running? XXX
|
|
*/
|
|
if(mm->num_active_bufs < 0 ||
|
|
mm->num_active_bufs > mtr->frames ||
|
|
mm->lowat < 1 || mm->lowat >= mtr->frames ||
|
|
mm->hiwat < 1 || mm->hiwat >= mtr->frames ||
|
|
mm->lowat > mm->hiwat ) {
|
|
*cap &= 0x8ff0;
|
|
mtr->flags &= ~(METEOR_SYNCAP|METEOR_WANT_MASK);
|
|
} else {
|
|
/*
|
|
* Ok, they are sane, now we want to
|
|
* check the water marks.
|
|
*/
|
|
if(mm->num_active_bufs <= mm->lowat)
|
|
mtr->synch_wait = 0;
|
|
if(mm->num_active_bufs >= mm->hiwat)
|
|
mtr->synch_wait = 1;
|
|
/*
|
|
* Clear the active frame bit for this frame
|
|
* and advance the counters if we are within
|
|
* the banks of the water marks.
|
|
*/
|
|
if(!mtr->synch_wait) {
|
|
mm->active &= ~(1 << mtr->current);
|
|
mtr->current++;
|
|
if(mtr->current > mtr->frames)
|
|
mtr->current = 1;
|
|
mm->num_active_bufs++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
*stat |= 0x7; /* clear interrupt status */
|
|
return;
|
|
}
|
|
|
|
static void
|
|
set_fps(meteor_reg_t *mtr, u_short fps)
|
|
{
|
|
struct saa7116_regs *s7116 = mtr->base;
|
|
unsigned status;
|
|
unsigned maxfps, mask = 0x1, length = 0;
|
|
|
|
SAA7196_WRITE(mtr, SAA7196_STDC, SAA7196_REG(mtr, SAA7196_STDC) | 0x02);
|
|
SAA7196_READ(mtr);
|
|
status = (s7116->i2c_read & 0xff000000L) >> 24;
|
|
|
|
/*
|
|
* Determine if there is an input signal. Depending on the
|
|
* frequency we either have a max of 25 fps (50 hz) or 30 fps (60 hz).
|
|
* If there is no input signal, then we need some defaults. If the
|
|
* user neglected to specify any defaults, just set to the fps to max.
|
|
*/
|
|
if((status & 0x40) == 0) { /* Is there a signal ? */
|
|
if(status & 0x20) {
|
|
maxfps = 30; /* 60 hz system */
|
|
} else {
|
|
maxfps = 25; /* 50 hz system */
|
|
}
|
|
} else { /* We have no signal, check defaults */
|
|
#if METEOR_SYSTEM_DEFAULT == METEOR_PAL || METEOR_SYSTEM_DEFAULT == METEOR_SECAM
|
|
maxfps = 25;
|
|
#elif METEOR_SYSTEM_DEFAULT == METEOR_NTSC
|
|
maxfps = 30;
|
|
#else
|
|
/* Don't really know what to do, just set max */
|
|
maxfps = 30;
|
|
fps = 30;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* A little sanity checking...
|
|
*/
|
|
if(fps < 1) fps = 1;
|
|
if(fps > maxfps) fps = maxfps;
|
|
|
|
/*
|
|
* Compute the mask/length using the fps.
|
|
*/
|
|
if(fps == maxfps) {
|
|
mask = 0x1;
|
|
length = 0x0;
|
|
} else if ((float)fps == maxfps/2.0) {
|
|
mask = 0x1;
|
|
length = 0x1;
|
|
} else if (fps > maxfps/2) {
|
|
float step, b;
|
|
|
|
mask = (1<<maxfps) - 1;
|
|
length = maxfps - 1;
|
|
step = (float)(maxfps - 1)/(float)(maxfps - fps);
|
|
for(b=step; b < maxfps; b += step) {
|
|
mask &= ~(1<<((int)b)); /* mask out the bth frame */
|
|
}
|
|
} else { /* fps < maxfps/2 */
|
|
float step, b;
|
|
|
|
mask = 0x1;
|
|
length = maxfps - 1;
|
|
step = (float)(maxfps -1)/(float)(fps);
|
|
for(b = step + 1; b < maxfps - 1; b += step) {
|
|
mask |= (1<<((int)b)); /* mask in the bth frame */
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Set the fps.
|
|
*/
|
|
s7116->fme = s7116->fmo = mask;
|
|
s7116->fml = (length << 16) | length;;
|
|
|
|
mtr->fps = fps;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/*
|
|
* There is also a problem with range checking on the 7116.
|
|
* It seems to only work for 22 bits, so the max size we can allocate
|
|
* is 22 bits long or 4194304 bytes assuming that we put the beginning
|
|
* of the buffer on a 2^24 bit boundary. The range registers will use
|
|
* the top 8 bits of the dma start registers along with the bottom 22
|
|
* bits of the range register to determine if we go out of range.
|
|
* This makes getting memory a real kludge.
|
|
*
|
|
*/
|
|
#define RANGE_BOUNDARY (1<<22)
|
|
static vm_offset_t
|
|
get_meteor_mem(int unit, unsigned size)
|
|
{
|
|
vm_offset_t addr = 0;
|
|
|
|
addr = vm_page_alloc_contig(size, 0x100000, 0xffffffff, 1<<24);
|
|
if(addr == 0)
|
|
addr = vm_page_alloc_contig(size, 0x100000, 0xffffffff,
|
|
PAGE_SIZE);
|
|
if(addr == 0) {
|
|
printf("meteor%d: Unable to allocate %d bytes of memory.\n",
|
|
unit, size);
|
|
}
|
|
|
|
return addr;
|
|
}
|
|
|
|
static void
|
|
bt254_write(meteor_reg_t *mtr, u_char addr, u_char data)
|
|
{
|
|
addr &= 0x7; /* sanity? */
|
|
mtr->bt254_reg[addr] = data;
|
|
PCF8574_DATA_WRITE(mtr, data); /* set data */
|
|
PCF8574_CTRL_WRITE(mtr, (PCF8574_CTRL_REG(mtr) & ~0x7) | addr);
|
|
PCF8574_CTRL_WRITE(mtr, PCF8574_CTRL_REG(mtr) & ~0x10); /* WR/ to 0 */
|
|
PCF8574_CTRL_WRITE(mtr, PCF8574_CTRL_REG(mtr) | 0x10); /* WR to 1 */
|
|
PCF8574_DATA_WRITE(mtr, 0xff); /* clr data */
|
|
|
|
}
|
|
|
|
static void
|
|
bt254_init(meteor_reg_t *mtr)
|
|
{
|
|
int i;
|
|
|
|
PCF8574_CTRL_WRITE(mtr, 0x7f);
|
|
PCF8574_DATA_WRITE(mtr, 0xff); /* data port must be 0xff */
|
|
PCF8574_CTRL_WRITE(mtr, 0x7f);
|
|
|
|
/* init RGB module for 24bpp, composite input */
|
|
for(i=0; i<NUM_BT254_REGS; i++)
|
|
bt254_write(mtr, i, bt254_default[i]);
|
|
|
|
bt254_write(mtr, BT254_COMMAND, 0x00); /* 24 bpp */
|
|
}
|
|
|
|
static void
|
|
bt254_ntsc(meteor_reg_t *mtr, int arg)
|
|
{
|
|
if (arg){
|
|
/* Set NTSC bit */
|
|
PCF8574_CTRL_WRITE(mtr, PCF8574_CTRL_REG(mtr) | 0x20);
|
|
}
|
|
else {
|
|
/* reset NTSC bit */
|
|
PCF8574_CTRL_WRITE(mtr, PCF8574_CTRL_REG(mtr) &= ~0x20);
|
|
}
|
|
}
|
|
|
|
static void
|
|
select_bt254(meteor_reg_t *mtr)
|
|
{
|
|
/* disable saa7196, saaen = 1 */
|
|
PCF8574_CTRL_WRITE(mtr, PCF8574_CTRL_REG(mtr) | 0x80);
|
|
/* enable Bt254, bten = 0 */
|
|
PCF8574_CTRL_WRITE(mtr, PCF8574_CTRL_REG(mtr) & ~0x40);
|
|
}
|
|
|
|
static void
|
|
select_saa7196(meteor_reg_t *mtr)
|
|
{
|
|
/* disable Bt254, bten = 1 */
|
|
PCF8574_CTRL_WRITE(mtr, PCF8574_CTRL_REG(mtr) | 0x40);
|
|
/* enable saa7196, saaen = 0 */
|
|
PCF8574_CTRL_WRITE(mtr, PCF8574_CTRL_REG(mtr) & ~0x80);
|
|
}
|
|
|
|
/*
|
|
* Initialize the 7116, 7196 and the RGB module.
|
|
*/
|
|
static void
|
|
meteor_init ( meteor_reg_t *mtr )
|
|
{
|
|
mreg_t *vbase_addr;
|
|
int i;
|
|
|
|
/*
|
|
* Initialize the Philips SAA7116
|
|
*/
|
|
mtr->base->cap_cntl = 0x00000040L;
|
|
vbase_addr = &mtr->base->dma1e;
|
|
for (i = 0 ; i < (sizeof(struct saa7116_regs)/sizeof(mreg_t)); i++)
|
|
*vbase_addr++ = saa7116_pci_default[i];
|
|
|
|
/*
|
|
* Check for the Philips SAA7196
|
|
*/
|
|
i2c_print_err = 0;
|
|
if(i2c_write(mtr, SAA7196_I2C_ADDR, SAA7116_I2C_WRITE, 0, 0xff) == 0) {
|
|
i2c_print_err = 1;
|
|
/*
|
|
* Initialize 7196
|
|
*/
|
|
for (i = 0; i < NUM_SAA7196_I2C_REGS; i++)
|
|
SAA7196_WRITE(mtr, i, saa7196_i2c_default[i]);
|
|
/*
|
|
* Get version number.
|
|
*/
|
|
SAA7196_WRITE(mtr, SAA7196_STDC,
|
|
SAA7196_REG(mtr, SAA7196_STDC) & ~0x02);
|
|
SAA7196_READ(mtr);
|
|
printf("meteor%d: <Philips SAA 7196> rev 0x%x\n",
|
|
METEOR_NUM(mtr),
|
|
(unsigned)((mtr->base->i2c_read & 0xff000000L) >> 28));
|
|
} else {
|
|
i2c_print_err = 1;
|
|
printf("meteor%d: <Philips SAA 7196 NOT FOUND>\n",
|
|
METEOR_NUM(mtr));
|
|
}
|
|
/*
|
|
* Check for RGB module, initialized if found.
|
|
*/
|
|
i2c_print_err = 0;
|
|
if(i2c_write(mtr,PCF8574_DATA_I2C_ADDR,SAA7116_I2C_WRITE,0,0xff) == 0) {
|
|
i2c_print_err = 1;
|
|
printf("meteor%d: <Booktree 254 (RGB module)>\n",
|
|
METEOR_NUM(mtr)); /* does this have a rev #? */
|
|
bt254_init(mtr); /* Set up RGB module */
|
|
mtr->flags = METEOR_RGB;
|
|
} else {
|
|
i2c_print_err = 1;
|
|
mtr->flags = 0;
|
|
}
|
|
|
|
set_fps(mtr, 30);
|
|
|
|
}
|
|
|
|
static void
|
|
met_attach(pcici_t tag, int unit)
|
|
{
|
|
#ifdef METEOR_IRQ
|
|
u_long old_irq, new_irq;
|
|
#endif METEOR_IRQ
|
|
meteor_reg_t *mtr;
|
|
vm_offset_t buf;
|
|
u_long latency;
|
|
|
|
if (unit >= NMETEOR) {
|
|
printf("meteor%d: attach: only %d units configured.\n",
|
|
unit, NMETEOR);
|
|
printf("meteor%d: attach: invalid unit number.\n", unit);
|
|
return ;
|
|
}
|
|
|
|
mtr = &meteor[unit];
|
|
mtr->tag = tag;
|
|
pci_map_mem(tag, PCI_MAP_REG_START, (vm_offset_t *)&mtr->base,
|
|
&mtr->phys_base);
|
|
|
|
#ifdef METEOR_IRQ /* from the configuration file */
|
|
old_irq = pci_conf_read(tag, PCI_INTERRUPT_REG);
|
|
pci_conf_write(tag, PCI_INTERRUPT_REG, METEOR_IRQ);
|
|
new_irq = pci_conf_read(tag, PCI_INTERRUPT_REG);
|
|
printf("meteor%d: attach: irq changed from %d to %d\n",
|
|
unit, (old_irq & 0xff), (new_irq & 0xff));
|
|
#endif METEOR_IRQ
|
|
/* setup the interrupt handling routine */
|
|
pci_map_int(tag, meteor_intr, (void*) mtr, &net_imask);
|
|
|
|
/*
|
|
* PCI latency timer. 32 is a good value for 4 bus mastering slots, if
|
|
* you have more than for, then 16 would probably be a better value.
|
|
*
|
|
*/
|
|
#ifndef METEOR_DEF_LATENCY_VALUE
|
|
#define METEOR_DEF_LATENCY_VALUE 32
|
|
#endif
|
|
latency = pci_conf_read(tag, PCI_LATENCY_TIMER);
|
|
latency = (latency >> 8) & 0xff;
|
|
if(bootverbose) {
|
|
if(latency)
|
|
printf("meteor%d: PCI bus latency is", unit);
|
|
else
|
|
printf("meteor%d: PCI bus latency was 0 changing to",
|
|
unit);
|
|
}
|
|
if(!latency) {
|
|
latency = METEOR_DEF_LATENCY_VALUE;
|
|
pci_conf_write(tag, PCI_LATENCY_TIMER, latency<<8);
|
|
}
|
|
if(bootverbose) {
|
|
printf(" %lu.\n", latency);
|
|
}
|
|
|
|
meteor_init(mtr); /* set up saa7116, saa7196, and rgb module */
|
|
|
|
if(METEOR_ALLOC)
|
|
buf = get_meteor_mem(unit, METEOR_ALLOC);
|
|
else
|
|
buf = 0;
|
|
if(bootverbose) {
|
|
printf("meteor%d: buffer size %d, addr 0x%x\n",
|
|
unit, METEOR_ALLOC, vtophys(buf));
|
|
}
|
|
|
|
mtr->bigbuf = buf;
|
|
mtr->alloc_pages = METEOR_ALLOC_PAGES;
|
|
if(buf != 0) {
|
|
bzero((caddr_t) buf, METEOR_ALLOC);
|
|
buf = vtophys(buf);
|
|
/* 640x480 RGB 16 */
|
|
mtr->base->dma1e = buf;
|
|
mtr->base->dma1o = buf + 0x500;
|
|
mtr->base->dma_end_e =
|
|
mtr->base->dma_end_o = buf + METEOR_ALLOC;
|
|
}
|
|
/* 1 frame of 640x480 RGB 16 */
|
|
mtr->cols = 640;
|
|
mtr->rows = 480;
|
|
mtr->depth = 2; /* two bytes per pixel */
|
|
mtr->frames = 1; /* one frame */
|
|
|
|
mtr->flags |= METEOR_INITALIZED | METEOR_AUTOMODE | METEOR_DEV0 |
|
|
METEOR_RGB16;
|
|
#ifdef DEVFS
|
|
mtr->devfs_token = devfs_add_devswf(&meteor_cdevsw, unit,
|
|
DV_CHR, 0, 0, 0644, "meteor");
|
|
#endif
|
|
}
|
|
|
|
#define UNIT(x) ((x) & 0x07)
|
|
|
|
#ifdef unused
|
|
static int
|
|
meteor_reset(dev_t dev)
|
|
{
|
|
int unit = UNIT(minor(dev));
|
|
struct saa7116_regs *m;
|
|
|
|
if(unit >= NMETEOR)
|
|
return ENXIO;
|
|
|
|
m = meteor[unit].base;
|
|
|
|
m->cap_cntl = 0x0;
|
|
tsleep((caddr_t)m, METPRI, "Mreset", hz/50);
|
|
|
|
m->cap_cntl = 0x8ff0;
|
|
m->cap_cntl = 0x80c0;
|
|
m->cap_cntl = 0x8040;
|
|
tsleep((caddr_t)m, METPRI, "Mreset", hz/10);
|
|
m->cap_cntl = 0x80c0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
#endif
|
|
|
|
/*---------------------------------------------------------
|
|
**
|
|
** Meteor character device driver routines
|
|
**
|
|
**---------------------------------------------------------
|
|
*/
|
|
|
|
|
|
int
|
|
meteor_open(dev_t dev, int flags, int fmt, struct proc *p)
|
|
{
|
|
meteor_reg_t *mtr;
|
|
int unit;
|
|
int i;
|
|
|
|
unit = UNIT(minor(dev));
|
|
if (unit >= NMETEOR) /* unit out of range */
|
|
return(ENXIO);
|
|
|
|
mtr = &(meteor[unit]);
|
|
|
|
if (!(mtr->flags & METEOR_INITALIZED)) /* device not found */
|
|
return(ENXIO);
|
|
|
|
if (mtr->flags & METEOR_OPEN) /* device is busy */
|
|
return(EBUSY);
|
|
|
|
mtr->flags |= METEOR_OPEN;
|
|
/*
|
|
* Make sure that the i2c regs are set the same for each open.
|
|
*/
|
|
for(i=0; i< NUM_SAA7196_I2C_REGS; i++) {
|
|
SAA7196_WRITE(mtr, i, saa7196_i2c_default[i]);
|
|
}
|
|
|
|
mtr->fifo_errors = 0;
|
|
mtr->dma_errors = 0;
|
|
mtr->frames_captured = 0;
|
|
mtr->even_fields_captured = 0;
|
|
mtr->odd_fields_captured = 0;
|
|
mtr->proc = (struct proc *)0;
|
|
set_fps(mtr, 30);
|
|
#ifdef METEOR_TEST_VIDEO
|
|
mtr->video.addr = 0;
|
|
mtr->video.width = 0;
|
|
mtr->video.banksize = 0;
|
|
mtr->video.ramsize = 0;
|
|
#endif
|
|
|
|
return(0);
|
|
}
|
|
|
|
int
|
|
meteor_close(dev_t dev, int flags, int fmt, struct proc *p)
|
|
{
|
|
meteor_reg_t *mtr;
|
|
int unit;
|
|
#ifdef METEOR_DEALLOC_ABOVE
|
|
int temp;
|
|
#endif
|
|
|
|
unit = UNIT(minor(dev));
|
|
if (unit >= NMETEOR) /* unit out of range */
|
|
return(ENXIO);
|
|
|
|
mtr = &(meteor[unit]);
|
|
mtr->flags &= ~METEOR_OPEN;
|
|
|
|
if(mtr->flags & METEOR_SINGLE)
|
|
/* this should not happen, the read capture
|
|
should have completed or in the very least
|
|
recieved a signal before close is called. */
|
|
wakeup((caddr_t)mtr); /* continue read */
|
|
/*
|
|
* Turn off capture mode.
|
|
*/
|
|
mtr->base->cap_cntl = 0x8ff0;
|
|
mtr->flags &= ~(METEOR_CAP_MASK|METEOR_WANT_MASK);
|
|
|
|
#ifdef METEOR_DEALLOC_PAGES
|
|
if (mtr->bigbuf != NULL) {
|
|
kmem_free(kernel_map,mtr->bigbuf,(mtr->alloc_pages*PAGE_SIZE));
|
|
mtr->bigbuf = NULL;
|
|
mtr->alloc_pages = 0;
|
|
}
|
|
#else
|
|
#ifdef METEOR_DEALLOC_ABOVE
|
|
if (mtr->bigbuf != NULL && mtr->alloc_pages > METEOR_DEALLOC_ABOVE) {
|
|
temp = METEOR_DEALLOC_ABOVE - mtr->alloc_pages;
|
|
kmem_free(kernel_map,
|
|
mtr->bigbuf+((mtr->alloc_pages - temp) * PAGE_SIZE),
|
|
(temp * PAGE_SIZE));
|
|
mtr->alloc_pages = METEOR_DEALLOC_ABOVE;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
return(0);
|
|
}
|
|
|
|
static void
|
|
start_capture(meteor_reg_t *mtr, unsigned type)
|
|
{
|
|
mreg_t *cap = &mtr->base->cap_cntl;
|
|
|
|
mtr->flags |= type;
|
|
switch(mtr->flags & METEOR_ONLY_FIELDS_MASK) {
|
|
case METEOR_ONLY_EVEN_FIELDS:
|
|
mtr->flags |= METEOR_WANT_EVEN;
|
|
if(type == METEOR_SINGLE)
|
|
*cap = 0x0ff4 | mtr->range_enable;
|
|
else
|
|
*cap = 0x0ff1 | mtr->range_enable;
|
|
break;
|
|
case METEOR_ONLY_ODD_FIELDS:
|
|
mtr->flags |= METEOR_WANT_ODD;
|
|
if(type == METEOR_SINGLE)
|
|
*cap = 0x0ff8 | mtr->range_enable;
|
|
else
|
|
*cap = 0x0ff2 | mtr->range_enable;
|
|
break;
|
|
default:
|
|
mtr->flags |= METEOR_WANT_MASK;
|
|
if(type == METEOR_SINGLE)
|
|
*cap = 0x0ffc | mtr->range_enable;
|
|
else
|
|
*cap = 0x0ff3 | mtr->range_enable;
|
|
break;
|
|
}
|
|
}
|
|
|
|
int
|
|
meteor_read(dev_t dev, struct uio *uio, int ioflag)
|
|
{
|
|
meteor_reg_t *mtr;
|
|
int unit;
|
|
int status;
|
|
int count;
|
|
|
|
unit = UNIT(minor(dev));
|
|
if (unit >= NMETEOR) /* unit out of range */
|
|
return(ENXIO);
|
|
|
|
mtr = &(meteor[unit]);
|
|
if (mtr->bigbuf == 0)/* no frame buffer allocated (ioctl failed) */
|
|
return(ENOMEM);
|
|
|
|
if (mtr->flags & METEOR_CAP_MASK)
|
|
return(EIO); /* already capturing */
|
|
|
|
count = mtr->rows * mtr->cols * mtr->depth;
|
|
if (uio->uio_iov->iov_len < count)
|
|
return(EINVAL);
|
|
|
|
/* Start capture */
|
|
start_capture(mtr, METEOR_SINGLE);
|
|
|
|
status=tsleep((caddr_t)mtr, METPRI, "capturing", 0);
|
|
if (!status) /* successful capture */
|
|
status = uiomove((caddr_t)mtr->bigbuf, count, uio);
|
|
else
|
|
printf ("meteor%d: read: tsleep error %d\n", unit, status);
|
|
|
|
mtr->flags &= ~(METEOR_SINGLE | METEOR_WANT_MASK);
|
|
|
|
return(status);
|
|
}
|
|
|
|
int
|
|
meteor_write(dev_t dev, struct uio *uio, int ioflag)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
int
|
|
meteor_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *pr)
|
|
{
|
|
int error;
|
|
int unit;
|
|
unsigned int temp;
|
|
meteor_reg_t *mtr;
|
|
struct meteor_counts *cnt;
|
|
struct meteor_geomet *geo;
|
|
struct meteor_mem *mem;
|
|
struct meteor_capframe *frame;
|
|
#ifdef METEOR_TEST_VIDEO
|
|
struct meteor_video *video;
|
|
#endif
|
|
vm_offset_t buf;
|
|
struct saa7116_regs *base;
|
|
|
|
error = 0;
|
|
|
|
if (!arg) return(EINVAL);
|
|
unit = UNIT(minor(dev));
|
|
if (unit >= NMETEOR) /* unit out of range */
|
|
return(ENXIO);
|
|
|
|
mtr = &(meteor[unit]);
|
|
base = mtr->base;
|
|
|
|
switch (cmd) {
|
|
case METEORSTS:
|
|
if(*arg)
|
|
mtr->flags |= METEOR_WANT_TS;
|
|
else
|
|
mtr->flags &= ~METEOR_WANT_TS;
|
|
break;
|
|
case METEORGTS:
|
|
if(mtr->flags & METEOR_WANT_TS)
|
|
*arg = 1;
|
|
else
|
|
*arg = 0;
|
|
break;
|
|
#ifdef METEOR_TEST_VIDEO
|
|
case METEORGVIDEO:
|
|
video = (struct meteor_video *)arg;
|
|
video->addr = mtr->video.addr;
|
|
video->width = mtr->video.width;
|
|
video->banksize = mtr->video.banksize;
|
|
video->ramsize = mtr->video.ramsize;
|
|
break;
|
|
case METEORSVIDEO:
|
|
video = (struct meteor_video *)arg;
|
|
mtr->video.addr = video->addr;
|
|
mtr->video.width = video->width;
|
|
mtr->video.banksize = video->banksize;
|
|
mtr->video.ramsize = video->ramsize;
|
|
break;
|
|
#endif
|
|
case METEORSFPS:
|
|
set_fps(mtr, *(u_short *)arg);
|
|
break;
|
|
case METEORGFPS:
|
|
*(u_short *)arg = mtr->fps;
|
|
break;
|
|
case METEORSSIGNAL:
|
|
mtr->signal = *(int *) arg;
|
|
mtr->proc = pr;
|
|
break;
|
|
case METEORGSIGNAL:
|
|
*(int *)arg = mtr->signal;
|
|
break;
|
|
case METEORSTATUS: /* get 7196 status */
|
|
temp = 0;
|
|
SAA7196_WRITE(mtr, SAA7196_STDC,
|
|
SAA7196_REG(mtr, SAA7196_STDC) | 0x02);
|
|
SAA7196_READ(mtr);
|
|
temp |= (base->i2c_read & 0xff000000L) >> 24;
|
|
SAA7196_WRITE(mtr, SAA7196_STDC,
|
|
SAA7196_REG(mtr, SAA7196_STDC) & ~0x02);
|
|
SAA7196_READ(mtr);
|
|
temp |= (base->i2c_read & 0xff000000L) >> 16;
|
|
*(u_short *)arg = temp;
|
|
break;
|
|
case METEORSHUE: /* set hue */
|
|
SAA7196_WRITE(mtr, SAA7196_HUEC, *(char *)arg);
|
|
break;
|
|
case METEORGHUE: /* get hue */
|
|
*(char *)arg = SAA7196_REG(mtr, SAA7196_HUEC);
|
|
break;
|
|
case METEORSCHCV: /* set chrominance gain */
|
|
SAA7196_WRITE(mtr, SAA7196_CGAINR, *(char *)arg);
|
|
break;
|
|
case METEORGCHCV: /* get chrominance gain */
|
|
*(char *)arg = SAA7196_REG(mtr, SAA7196_CGAINR);
|
|
break;
|
|
case METEORSBRIG: /* set brightness */
|
|
SAA7196_WRITE(mtr, SAA7196_BRIG, *(char *)arg);
|
|
break;
|
|
case METEORGBRIG: /* get brightness */
|
|
*(char *)arg = SAA7196_REG(mtr, SAA7196_BRIG);
|
|
break;
|
|
case METEORSCSAT: /* set chroma saturation */
|
|
SAA7196_WRITE(mtr, SAA7196_CSAT, *(char *)arg);
|
|
break;
|
|
case METEORGCSAT: /* get chroma saturation */
|
|
*(char *)arg = SAA7196_REG(mtr, SAA7196_CSAT);
|
|
break;
|
|
case METEORSCONT: /* set contrast */
|
|
SAA7196_WRITE(mtr, SAA7196_CONT, *(char *)arg);
|
|
break;
|
|
case METEORGCONT: /* get contrast */
|
|
*(char *)arg = SAA7196_REG(mtr, SAA7196_CONT);
|
|
break;
|
|
case METEORSBT254:
|
|
if((mtr->flags & METEOR_RGB) == 0)
|
|
return EINVAL;
|
|
temp = *(unsigned short *)arg;
|
|
bt254_write(mtr, temp & 0xf, (temp & 0x0ff0) >> 4);
|
|
break;
|
|
case METEORGBT254:
|
|
if((mtr->flags & METEOR_RGB) == 0)
|
|
return EINVAL;
|
|
temp = *(unsigned short *)arg & 0x7;
|
|
*(unsigned short *)arg = mtr->bt254_reg[temp] << 4 | temp;
|
|
break;
|
|
case METEORSHWS: /* set horizontal window start */
|
|
SAA7196_WRITE(mtr, SAA7196_HWS, *(char *)arg);
|
|
break;
|
|
case METEORGHWS: /* get horizontal window start */
|
|
*(char *)arg = SAA7196_REG(mtr, SAA7196_HWS);
|
|
break;
|
|
case METEORSVWS: /* set vertical window start */
|
|
SAA7196_WRITE(mtr, SAA7196_VWS, *(char *)arg);
|
|
break;
|
|
case METEORGVWS: /* get vertical window start */
|
|
*(char *)arg = SAA7196_REG(mtr, SAA7196_VWS);
|
|
break;
|
|
case METEORSINPUT: /* set input device */
|
|
switch(*(unsigned long *)arg & METEOR_DEV_MASK) {
|
|
case 0: /* default */
|
|
case METEOR_INPUT_DEV0:
|
|
if(mtr->flags & METEOR_RGB)
|
|
select_saa7196(mtr);
|
|
mtr->flags = (mtr->flags & ~METEOR_DEV_MASK)
|
|
| METEOR_DEV0;
|
|
SAA7196_WRITE(mtr, 0x0e,
|
|
(SAA7196_REG(mtr, 0x0e) & ~0x3) | 0x0);
|
|
SAA7196_WRITE(mtr, 0x06,
|
|
(SAA7196_REG(mtr, 0x06) & ~0x80));
|
|
break;
|
|
case METEOR_INPUT_DEV1:
|
|
if(mtr->flags & METEOR_RGB)
|
|
select_saa7196(mtr);
|
|
mtr->flags = (mtr->flags & ~METEOR_DEV_MASK)
|
|
| METEOR_DEV1;
|
|
SAA7196_WRITE(mtr, 0x0e,
|
|
(SAA7196_REG(mtr, 0x0e) & ~0x3) | 0x1);
|
|
SAA7196_WRITE(mtr, 0x06,
|
|
(SAA7196_REG(mtr, 0x06) & ~0x80));
|
|
break;
|
|
case METEOR_INPUT_DEV2:
|
|
if(mtr->flags & METEOR_RGB)
|
|
select_saa7196(mtr);
|
|
mtr->flags = (mtr->flags & ~METEOR_DEV_MASK)
|
|
| METEOR_DEV2;
|
|
SAA7196_WRITE(mtr, 0x0e,
|
|
(SAA7196_REG(mtr, 0x0e) & ~0x3) | 0x2);
|
|
SAA7196_WRITE(mtr, 0x06,
|
|
(SAA7196_REG(mtr, 0x06) & ~0x80));
|
|
break;
|
|
case METEOR_INPUT_DEV3:
|
|
if(mtr->flags & METEOR_RGB)
|
|
select_saa7196(mtr);
|
|
mtr->flags = (mtr->flags & ~METEOR_DEV_MASK)
|
|
| METEOR_DEV3;
|
|
SAA7196_WRITE(mtr, 0x0e,
|
|
(SAA7196_REG(mtr, 0x0e) | 0x3));
|
|
SAA7196_WRITE(mtr, 0x06,
|
|
(SAA7196_REG(mtr, 0x06) & ~0x80) );
|
|
break;
|
|
case METEOR_INPUT_DEV_SVIDEO:
|
|
if(mtr->flags & METEOR_RGB)
|
|
select_saa7196(mtr);
|
|
mtr->flags = (mtr->flags & ~METEOR_DEV_MASK)
|
|
| METEOR_DEV_SVIDEO;
|
|
SAA7196_WRITE(mtr, 0x0e,
|
|
(SAA7196_REG(mtr, 0x0e) & ~0x3) | 0x2);
|
|
SAA7196_WRITE(mtr, 0x06,
|
|
(SAA7196_REG(mtr, 0x06) & ~0x80) | 0x80);
|
|
break;
|
|
case METEOR_INPUT_DEV_RGB:
|
|
if((mtr->flags & METEOR_RGB) == 0)
|
|
return EINVAL;
|
|
mtr->flags = (mtr->flags & ~METEOR_DEV_MASK)
|
|
| METEOR_DEV_RGB;
|
|
SAA7196_WRITE(mtr, 0x0e,
|
|
(SAA7196_REG(mtr, 0x0e) & ~0x3) | 0x3);
|
|
SAA7196_WRITE(mtr, 0x06,
|
|
(SAA7196_REG(mtr, 0x06) & ~0x80));
|
|
select_bt254(mtr);
|
|
SAA7196_WRITE(mtr, 0x0e, /* chn 3 for synch */
|
|
(SAA7196_REG(mtr, 0x0e) & ~0x3) | 0x3);
|
|
break;
|
|
default:
|
|
return EINVAL;
|
|
}
|
|
break;
|
|
case METEORGINPUT: /* get input device */
|
|
*(u_long *)arg = mtr->flags & METEOR_DEV_MASK;
|
|
break;
|
|
case METEORSFMT: /* set input format */
|
|
switch(*(unsigned long *)arg & METEOR_FORM_MASK ) {
|
|
case 0: /* default */
|
|
case METEOR_FMT_NTSC:
|
|
mtr->flags = (mtr->flags & ~METEOR_FORM_MASK) |
|
|
METEOR_NTSC;
|
|
SAA7196_WRITE(mtr, SAA7196_STDC,
|
|
(SAA7196_REG(mtr, SAA7196_STDC) & ~0x01));
|
|
SAA7196_WRITE(mtr, 0x0f,
|
|
(SAA7196_REG(mtr, 0x0f) & ~0xe0) | 0x40);
|
|
SAA7196_WRITE(mtr, 0x22, 0x80);
|
|
SAA7196_WRITE(mtr, 0x24,
|
|
(SAA7196_REG(mtr, 0x24) & ~0x0c) | 0x08);
|
|
SAA7196_WRITE(mtr, 0x26, 0xf0);
|
|
SAA7196_WRITE(mtr, 0x28,
|
|
(SAA7196_REG(mtr, 0x28) & ~0x0c)) ;
|
|
if(mtr->flags & METEOR_RGB){
|
|
bt254_ntsc(mtr, 1);
|
|
}
|
|
break;
|
|
case METEOR_FMT_PAL:
|
|
mtr->flags = (mtr->flags & ~METEOR_FORM_MASK) |
|
|
METEOR_PAL;
|
|
SAA7196_WRITE(mtr, SAA7196_STDC,
|
|
(SAA7196_REG(mtr, SAA7196_STDC) & ~0x01));
|
|
SAA7196_WRITE(mtr, 0x0f,
|
|
(SAA7196_REG(mtr, 0x0f) & ~0xe0));
|
|
SAA7196_WRITE(mtr, 0x22, 0x00);
|
|
SAA7196_WRITE(mtr, 0x24,
|
|
(SAA7196_REG(mtr, 0x24) | 0x0c));
|
|
SAA7196_WRITE(mtr, 0x26, 0x20);
|
|
SAA7196_WRITE(mtr, 0x28,
|
|
(SAA7196_REG(mtr, 0x28) & ~0x0c) | 0x04) ;
|
|
if(mtr->flags & METEOR_RGB){
|
|
bt254_ntsc(mtr, 0);
|
|
}
|
|
break;
|
|
case METEOR_FMT_SECAM:
|
|
mtr->flags = (mtr->flags & ~METEOR_FORM_MASK) |
|
|
METEOR_SECAM;
|
|
SAA7196_WRITE(mtr, SAA7196_STDC,
|
|
(SAA7196_REG(mtr, SAA7196_STDC) & ~0x01) | 0x1);
|
|
SAA7196_WRITE(mtr, 0x0f,
|
|
(SAA7196_REG(mtr, 0x0f) & ~0xe0) | 0x20);
|
|
SAA7196_WRITE(mtr, 0x22, 0x00);
|
|
SAA7196_WRITE(mtr, 0x24,
|
|
(SAA7196_REG(mtr, 0x24) | 0x0c));
|
|
SAA7196_WRITE(mtr, 0x26, 0x20);
|
|
SAA7196_WRITE(mtr, 0x28,
|
|
(SAA7196_REG(mtr, 0x28) & ~0x0c) | 0x04) ;
|
|
if(mtr->flags & METEOR_RGB){
|
|
bt254_ntsc(mtr, 0);
|
|
}
|
|
break;
|
|
case METEOR_FMT_AUTOMODE:
|
|
mtr->flags = (mtr->flags & ~METEOR_FORM_MASK) |
|
|
METEOR_AUTOMODE;
|
|
SAA7196_WRITE(mtr, SAA7196_STDC,
|
|
(SAA7196_REG(mtr, SAA7196_STDC) & ~0x01));
|
|
SAA7196_WRITE(mtr, 0x0f,
|
|
(SAA7196_REG(mtr, 0x0f) & ~0xe0) | 0x80);
|
|
break;
|
|
default:
|
|
return EINVAL;
|
|
}
|
|
break;
|
|
case METEORGFMT: /* get input format */
|
|
*(u_long *)arg = mtr->flags & METEOR_FORM_MASK;
|
|
break;
|
|
case METEORCAPTUR:
|
|
temp = mtr->flags;
|
|
switch (*(int *) arg) {
|
|
case METEOR_CAP_SINGLE:
|
|
if (mtr->bigbuf==0) /* no frame buffer allocated */
|
|
return(ENOMEM);
|
|
|
|
if (temp & METEOR_CAP_MASK)
|
|
return(EIO); /* already capturing */
|
|
|
|
start_capture(mtr, METEOR_SINGLE);
|
|
|
|
/* wait for capture to complete */
|
|
error=tsleep((caddr_t)mtr, METPRI, "capturing", 0);
|
|
if(error)
|
|
printf("meteor%d: ioctl: tsleep error %d\n",
|
|
unit, error);
|
|
mtr->flags &= ~(METEOR_SINGLE|METEOR_WANT_MASK);
|
|
break;
|
|
case METEOR_CAP_CONTINOUS:
|
|
if (mtr->bigbuf==0) /* no frame buffer allocated */
|
|
return(ENOMEM);
|
|
|
|
if (temp & METEOR_CAP_MASK)
|
|
return(EIO); /* already capturing */
|
|
|
|
start_capture(mtr, METEOR_CONTIN);
|
|
|
|
break;
|
|
case METEOR_CAP_STOP_CONT:
|
|
if (mtr->flags & METEOR_CONTIN) {
|
|
/* turn off capture */
|
|
base->cap_cntl = 0x8ff0;
|
|
mtr->flags &= ~(METEOR_CONTIN|METEOR_WANT_MASK);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
error = EINVAL;
|
|
break;
|
|
}
|
|
break;
|
|
case METEORCAPFRM:
|
|
frame = (struct meteor_capframe *) arg;
|
|
if (!frame)
|
|
return(EINVAL);
|
|
switch (frame->command) {
|
|
case METEOR_CAP_N_FRAMES:
|
|
if (mtr->flags & METEOR_CAP_MASK)
|
|
return(EIO);
|
|
if (mtr->flags & (METEOR_YUV_PLANAR | METEOR_YUV_422)) /* XXX */
|
|
return(EINVAL); /* should fix intr so we allow these */
|
|
if (mtr->bigbuf == 0)
|
|
return(ENOMEM);
|
|
if ((mtr->frames < 2) ||
|
|
(frame->lowat < 1 || frame->lowat >= mtr->frames) ||
|
|
(frame->hiwat < 1 || frame->hiwat >= mtr->frames) ||
|
|
(frame->lowat > frame->hiwat))
|
|
return(EINVAL);
|
|
/* meteor_mem structure is on the page after the data */
|
|
mem = mtr->mem = (struct meteor_mem *) (mtr->bigbuf +
|
|
(round_page(mtr->frame_size * mtr->frames)));
|
|
mtr->current = 1;
|
|
mtr->synch_wait = 0;
|
|
mem->num_bufs = mtr->frames;
|
|
mem->frame_size= mtr->frame_size;
|
|
/* user and kernel change these */
|
|
mem->lowat = frame->lowat;
|
|
mem->hiwat = frame->hiwat;
|
|
mem->active = 0;
|
|
mem->num_active_bufs = 0;
|
|
/* Start capture */
|
|
start_capture(mtr, METEOR_SYNCAP);
|
|
break;
|
|
case METEOR_CAP_STOP_FRAMES:
|
|
if (mtr->flags & METEOR_SYNCAP) {
|
|
/* turn off capture */
|
|
base->cap_cntl = 0x8ff0;
|
|
mtr->flags &= ~(METEOR_SYNCAP|METEOR_WANT_MASK);
|
|
}
|
|
break;
|
|
case METEOR_HALT_N_FRAMES:
|
|
if(mtr->flags & METEOR_SYNCAP) {
|
|
base->cap_cntl = 0x8ff0;
|
|
mtr->flags &= ~(METEOR_WANT_MASK);
|
|
}
|
|
break;
|
|
case METEOR_CONT_N_FRAMES:
|
|
if(!(mtr->flags & METEOR_SYNCAP)) {
|
|
error = EINVAL;
|
|
break;
|
|
}
|
|
start_capture(mtr, METEOR_SYNCAP);
|
|
break;
|
|
default:
|
|
error = EINVAL;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case METEORSETGEO:
|
|
geo = (struct meteor_geomet *) arg;
|
|
|
|
/* Either even or odd, if even & odd, then these a zero */
|
|
if((geo->oformat & METEOR_GEO_ODD_ONLY) &&
|
|
(geo->oformat & METEOR_GEO_EVEN_ONLY)) {
|
|
printf("meteor%d: ioctl: Geometry odd or even only.\n",
|
|
unit);
|
|
return EINVAL;
|
|
}
|
|
/* set/clear even/odd flags */
|
|
if(geo->oformat & METEOR_GEO_ODD_ONLY)
|
|
mtr->flags |= METEOR_ONLY_ODD_FIELDS;
|
|
else
|
|
mtr->flags &= ~METEOR_ONLY_ODD_FIELDS;
|
|
if(geo->oformat & METEOR_GEO_EVEN_ONLY)
|
|
mtr->flags |= METEOR_ONLY_EVEN_FIELDS;
|
|
else
|
|
mtr->flags &= ~METEOR_ONLY_EVEN_FIELDS;
|
|
|
|
/* can't change parameters while capturing */
|
|
if (mtr->flags & METEOR_CAP_MASK)
|
|
return(EBUSY);
|
|
|
|
if ((geo->columns & 0x3fe) != geo->columns) {
|
|
printf(
|
|
"meteor%d: ioctl: %d: columns too large or not even.\n",
|
|
unit, geo->columns);
|
|
error = EINVAL;
|
|
}
|
|
if (((geo->rows & 0x7fe) != geo->rows) ||
|
|
((geo->oformat & METEOR_GEO_FIELD_MASK) &&
|
|
((geo->rows & 0x3fe) != geo->rows)) ) {
|
|
printf(
|
|
"meteor%d: ioctl: %d: rows too large or not even.\n",
|
|
unit, geo->rows);
|
|
error = EINVAL;
|
|
}
|
|
if (geo->frames > 32) {
|
|
printf("meteor%d: ioctl: too many frames.\n", unit);
|
|
error = EINVAL;
|
|
}
|
|
if(error) return error;
|
|
|
|
if ((temp=geo->rows * geo->columns * geo->frames * 2) != 0) {
|
|
if (geo->oformat & METEOR_GEO_RGB24) temp = temp * 2;
|
|
|
|
/* meteor_mem structure for SYNC Capture */
|
|
if (geo->frames > 1) temp += PAGE_SIZE;
|
|
|
|
temp = btoc(temp);
|
|
if (temp > mtr->alloc_pages
|
|
#ifdef METEOR_TEST_VIDEO
|
|
&& mtr->video.addr == 0
|
|
#endif
|
|
) {
|
|
buf = get_meteor_mem(unit, temp*PAGE_SIZE);
|
|
if(buf != 0) {
|
|
kmem_free(kernel_map, mtr->bigbuf,
|
|
(mtr->alloc_pages * PAGE_SIZE));
|
|
mtr->bigbuf = buf;
|
|
mtr->alloc_pages = temp;
|
|
if(bootverbose)
|
|
printf(
|
|
"meteor%d: ioctl: Allocating %d bytes\n",
|
|
unit, temp*PAGE_SIZE);
|
|
} else {
|
|
error = ENOMEM;
|
|
}
|
|
}
|
|
}
|
|
if(error) return error;
|
|
|
|
mtr->rows = geo->rows;
|
|
mtr->cols = geo->columns;
|
|
mtr->frames = geo->frames;
|
|
|
|
#ifdef METEOR_TEST_VIDEO
|
|
if(mtr->video.addr)
|
|
buf = vtophys(mtr->video.addr);
|
|
else
|
|
#endif
|
|
buf = vtophys(mtr->bigbuf);
|
|
|
|
/* set defaults and end of buffer locations */
|
|
base->dma1e = buf;
|
|
base->dma2e = buf;
|
|
base->dma3e = buf;
|
|
base->dma1o = buf;
|
|
base->dma2o = buf;
|
|
base->dma3o = buf;
|
|
base->stride1e = 0;
|
|
base->stride2e = 0;
|
|
base->stride3e = 0;
|
|
base->stride1o = 0;
|
|
base->stride2o = 0;
|
|
base->stride3o = 0;
|
|
/* set end of DMA location, even/odd */
|
|
base->dma_end_e =
|
|
base->dma_end_o = buf + mtr->alloc_pages * PAGE_SIZE;
|
|
|
|
/*
|
|
* Determine if we can use the hardware range detect.
|
|
*/
|
|
if(mtr->alloc_pages * PAGE_SIZE < RANGE_BOUNDARY &&
|
|
((buf & 0xff000000) | base->dma_end_e) ==
|
|
(buf + mtr->alloc_pages * PAGE_SIZE) )
|
|
mtr->range_enable = 0x8000;
|
|
else {
|
|
mtr->range_enable = 0x0;
|
|
base->dma_end_e =
|
|
base->dma_end_o = 0xffffffff;
|
|
}
|
|
|
|
|
|
switch (geo->oformat & METEOR_GEO_OUTPUT_MASK) {
|
|
case 0: /* default */
|
|
case METEOR_GEO_RGB16:
|
|
mtr->depth = 2;
|
|
mtr->frame_size = mtr->rows * mtr->cols * mtr->depth;
|
|
mtr->flags &= ~METEOR_OUTPUT_FMT_MASK;
|
|
mtr->flags |= METEOR_RGB16;
|
|
temp = mtr->cols * mtr->depth;
|
|
/* recal stride and starting point */
|
|
switch(mtr->flags & METEOR_ONLY_FIELDS_MASK) {
|
|
case METEOR_ONLY_ODD_FIELDS:
|
|
base->dma1o = buf;
|
|
#ifdef METEOR_TEST_VIDEO
|
|
if(mtr->video.addr && mtr->video.width)
|
|
base->stride1o = mtr->video.width-temp;
|
|
#endif
|
|
SAA7196_WRITE(mtr, 0x20, 0xd0);
|
|
break;
|
|
case METEOR_ONLY_EVEN_FIELDS:
|
|
base->dma1e = buf;
|
|
#ifdef METEOR_TEST_VIDEO
|
|
if(mtr->video.addr && mtr->video.width)
|
|
base->stride1e = mtr->video.width-temp;
|
|
#endif
|
|
SAA7196_WRITE(mtr, 0x20, 0xf0);
|
|
break;
|
|
default: /* interlaced even/odd */
|
|
base->dma1e = buf;
|
|
base->dma1o = buf + temp;
|
|
base->stride1e = base->stride1o = temp;
|
|
#ifdef METEOR_TEST_VIDEO
|
|
if(mtr->video.addr && mtr->video.width) {
|
|
base->dma1o = buf + mtr->video.width;
|
|
base->stride1e = base->stride1o =
|
|
mtr->video.width -
|
|
temp + mtr->video.width;
|
|
}
|
|
#endif
|
|
SAA7196_WRITE(mtr, 0x20, 0x90);
|
|
break;
|
|
}
|
|
base->routee = base->routeo = 0xeeeeee01;
|
|
break;
|
|
case METEOR_GEO_RGB24:
|
|
mtr->depth = 4;
|
|
mtr->frame_size = mtr->rows * mtr->cols * mtr->depth;
|
|
mtr->flags &= ~METEOR_OUTPUT_FMT_MASK;
|
|
mtr->flags |= METEOR_RGB24;
|
|
temp = mtr->cols * mtr->depth;
|
|
/* recal stride and starting point */
|
|
switch(mtr->flags & METEOR_ONLY_FIELDS_MASK) {
|
|
case METEOR_ONLY_ODD_FIELDS:
|
|
base->dma1o = buf;
|
|
#ifdef METEOR_TEST_VIDEO
|
|
if(mtr->video.addr && mtr->video.width)
|
|
base->stride1o = mtr->video.width-temp;
|
|
#endif
|
|
SAA7196_WRITE(mtr, 0x20, 0xd2);
|
|
break;
|
|
case METEOR_ONLY_EVEN_FIELDS:
|
|
base->dma1e = buf;
|
|
#ifdef METEOR_TEST_VIDEO
|
|
if(mtr->video.addr && mtr->video.width)
|
|
base->stride1e = mtr->video.width-temp;
|
|
#endif
|
|
SAA7196_WRITE(mtr, 0x20, 0xf2);
|
|
break;
|
|
default: /* interlaced even/odd */
|
|
base->dma1e = buf;
|
|
base->dma1o = buf + mtr->cols * mtr->depth;
|
|
base->stride1e = base->stride1o =
|
|
mtr->cols * mtr->depth;
|
|
#ifdef METEOR_TEST_VIDEO
|
|
if(mtr->video.addr && mtr->video.width) {
|
|
base->dma1o = buf + mtr->video.width;
|
|
base->stride1e = base->stride1o =
|
|
mtr->video.width -
|
|
temp + mtr->video.width;
|
|
}
|
|
#endif
|
|
SAA7196_WRITE(mtr, 0x20, 0x92);
|
|
break;
|
|
}
|
|
base->routee= base->routeo= 0x39393900;
|
|
break;
|
|
case METEOR_GEO_YUV_PLANAR:
|
|
mtr->depth = 2;
|
|
temp = mtr->rows * mtr->cols; /* compute frame size */
|
|
mtr->frame_size = temp * mtr->depth;
|
|
mtr->flags &= ~METEOR_OUTPUT_FMT_MASK;
|
|
mtr->flags |= METEOR_YUV_PLANAR;
|
|
/* recal stride and starting point */
|
|
switch(mtr->flags & METEOR_ONLY_FIELDS_MASK) {
|
|
case METEOR_ONLY_ODD_FIELDS:
|
|
base->dma1o = buf; /* Y Odd */
|
|
base->dma2o = buf + temp; /* U Odd */
|
|
temp >>= 1;
|
|
base->dma3o = base->dma2o + temp; /* V Odd */
|
|
SAA7196_WRITE(mtr, 0x20, 0xd1);
|
|
break;
|
|
case METEOR_ONLY_EVEN_FIELDS:
|
|
base->dma1e = buf; /* Y Even */
|
|
base->dma2e = buf + temp; /* U Even */
|
|
temp >>= 1;
|
|
base->dma2e= base->dma2e + temp; /* V Even */
|
|
SAA7196_WRITE(mtr, 0x20, 0xf1);
|
|
break;
|
|
default: /* interlaced even/odd */
|
|
base->dma1e = buf; /* Y Even */
|
|
base->dma2e = buf + temp; /* U Even */
|
|
temp >>= 2;
|
|
base->dma3e = base->dma2e + temp; /* V Even */
|
|
base->dma1o = base->dma1e+mtr->cols;/* Y Odd */
|
|
base->dma2o = base->dma3e + temp; /* U Odd */
|
|
base->dma3o = base->dma2o + temp; /* V Odd */
|
|
base->stride1e = base->stride1o = mtr->cols;
|
|
SAA7196_WRITE(mtr, 0x20, 0x91);
|
|
break;
|
|
}
|
|
switch (geo->oformat &
|
|
(METEOR_GEO_YUV_12 | METEOR_GEO_YUV_9)) {
|
|
case METEOR_GEO_YUV_9:
|
|
base->routee=base->routeo = 0xaaaaffc3;
|
|
break;
|
|
case METEOR_GEO_YUV_12:
|
|
base->routee=base->routeo = 0xaaaaffc2;
|
|
break;
|
|
default:
|
|
base->routee=base->routeo = 0xaaaaffc1;
|
|
break;
|
|
}
|
|
break;
|
|
case METEOR_GEO_YUV_422:/* same as planer, different uv order */
|
|
mtr->depth = 2;
|
|
temp = mtr->rows * mtr->cols; /* compute frame size */
|
|
mtr->frame_size = temp * mtr->depth;
|
|
mtr->flags &= ~METEOR_OUTPUT_FMT_MASK;
|
|
mtr->flags |= METEOR_YUV_422;
|
|
switch(mtr->flags & METEOR_ONLY_FIELDS_MASK) {
|
|
case METEOR_ONLY_ODD_FIELDS:
|
|
base->dma1o = buf;
|
|
base->dma2o = buf + temp;
|
|
base->dma3o = base->dma2o + (temp >> 1);
|
|
SAA7196_WRITE(mtr, 0x20, 0xd1);
|
|
break;
|
|
case METEOR_ONLY_EVEN_FIELDS:
|
|
base->dma1e = buf;
|
|
base->dma2e = buf + temp;
|
|
base->dma3e = base->dma2e + (temp >> 1);
|
|
SAA7196_WRITE(mtr, 0x20, 0xf1);
|
|
break;
|
|
default: /* interlaced even/odd */
|
|
base->dma1e = buf; /* Y even */
|
|
base->dma2e = buf + temp; /* U even */
|
|
base->dma3e =
|
|
base->dma2e + (temp >> 1);/* V even */
|
|
base->dma1o = base->dma1e+mtr->cols;/* Y odd */
|
|
temp = mtr->cols >> 1;
|
|
base->dma2o = base->dma2e+temp; /* U odd */
|
|
base->dma3o = base->dma3e+temp; /* V odd */
|
|
base->stride1e =
|
|
base->stride1o = mtr->cols; /* Y stride */
|
|
base->stride2e =
|
|
base->stride2o = temp; /* U stride */
|
|
base->stride3e =
|
|
base->stride3o = temp; /* V stride */
|
|
SAA7196_WRITE(mtr, 0x20, 0x91);
|
|
break;
|
|
}
|
|
switch (geo->oformat &
|
|
(METEOR_GEO_YUV_12 | METEOR_GEO_YUV_9)) {
|
|
case METEOR_GEO_YUV_9:
|
|
base->routee=base->routeo = 0xaaaaffc3;
|
|
break;
|
|
case METEOR_GEO_YUV_12:
|
|
base->routee=base->routeo = 0xaaaaffc2;
|
|
break;
|
|
default:
|
|
base->routee=base->routeo = 0xaaaaffc1;
|
|
break;
|
|
}
|
|
break;
|
|
case METEOR_GEO_YUV_PACKED:
|
|
mtr->depth = 2;
|
|
mtr->frame_size = mtr->rows * mtr->cols * mtr->depth;
|
|
mtr->flags &= ~METEOR_OUTPUT_FMT_MASK;
|
|
mtr->flags |= METEOR_YUV_PACKED;
|
|
/* recal stride and odd starting point */
|
|
switch(mtr->flags & METEOR_ONLY_FIELDS_MASK) {
|
|
case METEOR_ONLY_ODD_FIELDS:
|
|
base->dma1o = buf;
|
|
SAA7196_WRITE(mtr, 0x20, 0xd1);
|
|
break;
|
|
case METEOR_ONLY_EVEN_FIELDS:
|
|
base->dma1e = buf;
|
|
SAA7196_WRITE(mtr, 0x20, 0xf1);
|
|
break;
|
|
default: /* interlaced even/odd */
|
|
base->dma1e = buf;
|
|
base->dma1o = buf + mtr->cols * mtr->depth;
|
|
base->stride1e = base->stride1o =
|
|
mtr->cols * mtr->depth;
|
|
SAA7196_WRITE(mtr, 0x20, 0x91);
|
|
break;
|
|
}
|
|
base->routee = base->routeo = 0xeeeeee41;
|
|
break;
|
|
default:
|
|
error = EINVAL; /* invalid argument */
|
|
printf("meteor%d: ioctl: invalid output format\n",unit);
|
|
break;
|
|
}
|
|
/* set cols */
|
|
SAA7196_WRITE(mtr, 0x21, mtr->cols & 0xff);
|
|
SAA7196_WRITE(mtr, 0x24,
|
|
((SAA7196_REG(mtr, 0x24) & ~0x03) |
|
|
((mtr->cols >> 8) & 0x03)));
|
|
/* set rows */
|
|
if(mtr->flags & METEOR_ONLY_FIELDS_MASK) {
|
|
SAA7196_WRITE(mtr, 0x25, ((mtr->rows) & 0xff));
|
|
SAA7196_WRITE(mtr, 0x28,
|
|
((SAA7196_REG(mtr, 0x28) & ~0x03) |
|
|
((mtr->rows >> 8) & 0x03)));
|
|
} else { /* Interlaced */
|
|
SAA7196_WRITE(mtr, 0x25, ((mtr->rows >> 1) & 0xff));
|
|
SAA7196_WRITE(mtr, 0x28,
|
|
((SAA7196_REG(mtr, 0x28) & ~0x03) |
|
|
((mtr->rows >> 9) & 0x03)));
|
|
}
|
|
/* set signed/unsigned chrominance */
|
|
SAA7196_WRITE(mtr, 0x30, (SAA7196_REG(mtr, 0x30) & ~0x10) |
|
|
((geo->oformat&METEOR_GEO_UNSIGNED)?0:0x10));
|
|
break;
|
|
case METEORGETGEO:
|
|
geo = (struct meteor_geomet *) arg;
|
|
geo->rows = mtr->rows;
|
|
geo->columns = mtr->cols;
|
|
geo->frames = mtr->frames;
|
|
geo->oformat = (mtr->flags & METEOR_OUTPUT_FMT_MASK) |
|
|
(mtr->flags & METEOR_ONLY_FIELDS_MASK) |
|
|
(SAA7196_REG(mtr, 0x30) & 0x10 ?
|
|
0:METEOR_GEO_UNSIGNED);
|
|
switch(base->routee & 0xff) {
|
|
case 0xc3:
|
|
geo->oformat |= METEOR_GEO_YUV_9;
|
|
break;
|
|
case 0xc2:
|
|
geo->oformat |= METEOR_GEO_YUV_12;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case METEORSCOUNT: /* (re)set error counts */
|
|
cnt = (struct meteor_counts *) arg;
|
|
mtr->fifo_errors = cnt->fifo_errors;
|
|
mtr->dma_errors = cnt->dma_errors;
|
|
mtr->frames_captured = cnt->frames_captured;
|
|
mtr->even_fields_captured = cnt->even_fields_captured;
|
|
mtr->odd_fields_captured = cnt->odd_fields_captured;
|
|
break;
|
|
case METEORGCOUNT: /* get error counts */
|
|
cnt = (struct meteor_counts *) arg;
|
|
cnt->fifo_errors = mtr->fifo_errors;
|
|
cnt->dma_errors = mtr->dma_errors;
|
|
cnt->frames_captured = mtr->frames_captured;
|
|
cnt->even_fields_captured = mtr->even_fields_captured;
|
|
cnt->odd_fields_captured = mtr->odd_fields_captured;
|
|
break;
|
|
default:
|
|
printf("meteor%d: ioctl: invalid ioctl request\n", unit);
|
|
error = ENOTTY;
|
|
break;
|
|
}
|
|
return(error);
|
|
}
|
|
|
|
int
|
|
meteor_mmap(dev_t dev, vm_offset_t offset, int nprot)
|
|
{
|
|
|
|
int unit;
|
|
meteor_reg_t *mtr;
|
|
|
|
unit = UNIT(minor(dev));
|
|
if (unit >= NMETEOR) /* at this point could this happen? */
|
|
return(-1);
|
|
|
|
mtr = &(meteor[unit]);
|
|
|
|
|
|
if(nprot & PROT_EXEC)
|
|
return -1;
|
|
|
|
if(offset >= mtr->alloc_pages * PAGE_SIZE)
|
|
return -1;
|
|
|
|
return i386_btop(vtophys(mtr->bigbuf) + offset);
|
|
}
|
|
|
|
|
|
#if !defined(METEOR_FreeBSD_210) /* XXX */
|
|
static int meteor_devsw_installed;
|
|
|
|
static void meteor_drvinit(void *unused)
|
|
{
|
|
dev_t dev;
|
|
|
|
if( ! meteor_devsw_installed ) {
|
|
dev = makedev(CDEV_MAJOR, 0);
|
|
cdevsw_add(&dev,&meteor_cdevsw, NULL);
|
|
meteor_devsw_installed = 1;
|
|
}
|
|
}
|
|
|
|
SYSINIT(meteordev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,meteor_drvinit,NULL)
|
|
#endif
|
|
|
|
#endif /* NMETEOR > 0 */
|