summaryrefslogtreecommitdiffstats
path: root/sys/pci/meteor.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/pci/meteor.c')
-rw-r--r--sys/pci/meteor.c1040
1 files changed, 697 insertions, 343 deletions
diff --git a/sys/pci/meteor.c b/sys/pci/meteor.c
index db8ef12..14b4314 100644
--- a/sys/pci/meteor.c
+++ b/sys/pci/meteor.c
@@ -40,6 +40,53 @@
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.
+ Add option (METEOR_FreeBSD_210) for FreeBSD 2.1
+ to compile.
*/
#include "meteor.h"
@@ -64,6 +111,7 @@
#include <sys/devfsext.h>
#endif /* DEVFS */
#include <machine/clock.h>
+#include <machine/cpu.h> /* bootverbose */
#include <vm/vm.h>
#include <vm/vm_kern.h>
@@ -74,18 +122,22 @@
#include <pci.h>
#if NPCI > 0
#include <pci/pcivar.h>
+#include <pci/pcireg.h>
#endif
#include <machine/ioctl_meteor.h>
static int meteor_intr __P((void *arg));
- /* enough memory for 640x48 RGB16, or YUV (16 storage bits/pixel) or
- 450x340 RGB24 (32 storage bits/pixel)
- options "METEOR_ALLOC_PAGES="
- */
+/*
+ * 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 151
+#define METEOR_ALLOC_PAGES 217
#endif
#define METEOR_ALLOC (METEOR_ALLOC_PAGES * PAGE_SIZE)
@@ -102,10 +154,10 @@ typedef struct {
vm_offset_t bigbuf; /* buffer that holds the captured image */
int alloc_pages; /* number of pages in bigbuf */
struct proc *proc; /* process to receive raised signal */
+ int signal; /* signal to send to process */
struct meteor_mem *mem; /* used to control sync. multi-frame output */
- u_long hiwat_cnt; /* mark and count frames lost due to hiwat */
- short ecurrent; /* even frame number in buffer (1-frames) */
- short ocurrent; /* odd frame number in buffer (1-frames) */
+ u_long synch_wait; /* wait for free buffer before continuing */
+ short current; /* frame number in buffer (1-frames) */
short rows; /* number of rows in a frame */
short cols; /* number of columns in a frame */
short depth; /* number of byte per pixel */
@@ -114,15 +166,17 @@ typedef struct {
u_long fifo_errors; /* number of fifo capture errors since open */
u_long dma_errors; /* number of DMA capture errors since open */
u_long frames_captured;/* number of frames captured since open */
+ u_long even_fields_captured; /* number of even fields captured */
+ u_long odd_fields_captured; /* number of odd fields captured */
unsigned flags;
#define METEOR_INITALIZED 0x00000001
#define METEOR_OPEN 0x00000002
#define METEOR_MMAP 0x00000004
#define METEOR_INTR 0x00000008
-#define METEOR_READ 0x00000010
-#define METEOR_SINGLE 0x00000020
-#define METEOR_CONTIN 0x00000040
-#define METEOR_SYNCAP 0x00000080
+#define METEOR_READ 0x00000010 /* XXX never gets referenced */
+#define METEOR_SINGLE 0x00000020 /* get single frame */
+#define METEOR_CONTIN 0x00000040 /* continuously get frames */
+#define METEOR_SYNCAP 0x00000080 /* synchronously get frames */
#define METEOR_CAP_MASK 0x000000f0
#define METEOR_NTSC 0x00000100
#define METEOR_PAL 0x00000200
@@ -138,11 +192,16 @@ typedef struct {
#define METEOR_RGB24 0x00020000
#define METEOR_YUV_PACKED 0x00040000
#define METEOR_YUV_PLANER 0x00080000
-#define METEOR_PRO_MASK 0x000f0000
-#define METEOR_SINGLE_EVEN 0x00100000
-#define METEOR_SINGLE_ODD 0x00200000
-#define METEOR_SINGLE_MASK 0x00300000
+#define METEOR_WANT_EVEN 0x00100000 /* want even frame */
+#define METEOR_WANT_ODD 0x00200000 /* want odd frame */
+#define METEOR_WANT_MASK 0x00300000
+#define METEOR_ONLY_EVEN_FIELDS 0x01000000
+#define METEOR_ONLY_ODD_FIELDS 0x02000000
+#define METEOR_ONLY_FIELDS_MASK 0x03000000
+#define METEOR_YUV_422 0x04000000
+#define METEOR_OUTPUT_FMT_MASK 0x040f0000
u_char saa7196_i2c[NUM_SAA7196_I2C_REGS]; /* saa7196 register values */
+ u_short fps; /* frames per second */
#ifdef DEVFS
void *devfs_token;
#endif
@@ -150,7 +209,6 @@ typedef struct {
static meteor_reg_t meteor[NMETEOR];
-static u_long read_intr_wait;
#define METPRI (PZERO+8)|PCATCH
/*---------------------------------------------------------
@@ -173,6 +231,14 @@ static struct pci_device met_device = {
DATA_SET (pcidevice_set, 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;
@@ -185,7 +251,7 @@ 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 u_long saa7116_pci_default[NUM_SAA7116_PCI_REGS] = {
/* PCI Memory registers */
@@ -220,7 +286,7 @@ static u_long saa7116_pci_default[NUM_SAA7116_PCI_REGS] = {
7:0 *RW Mode (Odd) */
/* 0x38 */ 0x00200020, /* 22:16 *RW FIFO Trigger Planer Mode,
6:0 *RW FIFO Trigger Packed Mode */
-/* 0x3c */ 0x00000103, /* 9:8 *RW Reserved (0x0)
+/* 0x3c */ 0x00000107, /* 9:8 *RW Reserved (0x0)
2 *RW Field Toggle
1 *RW Reserved (0x1)
0 *RW Reserved (0x1) */
@@ -238,7 +304,6 @@ static u_long saa7116_pci_default[NUM_SAA7116_PCI_REGS] = {
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
@@ -314,11 +379,11 @@ static u_char saa7196_i2c_default[NUM_SAA7196_I2C_REGS] = {
/* SAA7196 I2C bus control */
/* BITS Function */
/* 00 */ 0x50, /* 7:0 Increment Delay */
-/* 01 */ 0x7f, /* 7:0 Horizontal Sync Begin for 50hz */
-/* 02 */ 0x53, /* 7:0 Horizontal Sync Stop for 50hz */
-/* 03 */ 0x43, /* 7:0 Horizontal Sync Clamp Start for 50hz */
-/* 04 */ 0x19, /* 7:0 Horizontal Sync Clamp Stop for 50hz */
-/* 05 */ 0x00, /* 7:0 Horizontal Sync Start after PH1 for 50hz */
+/* 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
@@ -354,10 +419,14 @@ static u_char saa7196_i2c_default[NUM_SAA7196_I2C_REGS] = {
/* 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,
@@ -417,7 +486,7 @@ static u_char saa7196_i2c_default[NUM_SAA7196_I2C_REGS] = {
#define IIC_DIRECT_TRANSFER_ABORTED 0x0000200L
#define SAA7196_WRITE(mtr, reg, data) \
- i2c_write(mtr, SAA7196_I2C_ADDR, I2C_WRITE, reg, data); \
+ i2c_write(mtr, SAA7196_I2C_ADDR, I2C_WRITE, reg, data), \
mtr->saa7196_i2c[reg] = data
#define SAA7196_REG(mtr, reg) mtr->saa7196_i2c[reg]
#define SAA7196_READ(mtr) \
@@ -426,9 +495,9 @@ static u_char saa7196_i2c_default[NUM_SAA7196_I2C_REGS] = {
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 unsigned long wait_counter = 0x0001ffff;
register volatile u_long *iic_write_loc = (volatile u_long *)mtr->iic_virt_addr;
-register int err = 0;
+register int err = 0;
/* Write the data the the i2c write register */
*iic_write_loc = SAA7116_IIC_NEW_CYCLE |
@@ -441,21 +510,16 @@ register int err = 0;
wait_counter--;
}
-/*#ifdef notdef*/
- /* it seems the iic_write_loc is cached, until we can
- figure out how to uncache the pci registers, then we
- will just ignore the timeout. Hopefully 1ffff will
- be enough delay time for the i2c cycle to complete */
+ /* 1ffff should be enough delay time for the i2c cycle to complete */
if(!wait_counter) {
printf("meteor: saa7116 i2c %s transfer timeout 0x%x",
rw ? "read" : "write", *iic_write_loc);
err=1;
}
-/*#endif*/
/* Check for error on direct write, clear if any */
- if((*((volatile u_long *)mtr->stat_reg)) & IIC_DIRECT_TRANSFER_ABORTED) {
+ if((*((volatile u_long *)mtr->stat_reg)) & IIC_DIRECT_TRANSFER_ABORTED){
printf("meteor: saa7116 i2c %s tranfer aborted",
rw ? "read" : "write" );
err= 1;
@@ -485,81 +549,218 @@ met_probe (pcici_t tag, pcidi_t type)
complete meteor_read() if using interrupts
*/
static int
-meteor_intr( void *arg)
+meteor_intr(void *arg)
{
- register meteor_reg_t *mtr = (meteor_reg_t *) arg;
-
- register volatile u_long *cap, *base, *status, cap_err;
- struct meteor_mem *mm;
-
- base = (volatile u_long *) mtr->virt_baseaddr;
- cap = (volatile u_long *) mtr->capt_cntrl; /* capture control ptr */
- status = base + 18; /* mtr->virt_base + 0x48 save a dereference */
-
- /* the even field has to make the decision of whether the high water
- has been reached. If hiwat has been reach do not advance the buffer.
- continue to save frames on this buffer until we can advance again */
- if (*status & 0x1) { /* even field */
- if (mtr->flags & METEOR_SYNCAP) {
- mm = mtr->mem; /* shared SYNCAP struct */
- if ((!mtr->hiwat_cnt && mm->num_active_bufs < mm->hiwat) ||
- (mm->num_active_bufs <= mm->lowat)) {
- mtr->hiwat_cnt = 0;
- if (++mtr->ecurrent > mtr->frames) {
- *base = mtr->bigbuf;
- mtr->ecurrent = 1;
- } else {
- *base = *base + mtr->frame_size;
- }
- }
- else {
- mtr->hiwat_cnt++;
- }
- } else if(mtr->flags & METEOR_SINGLE) {
- *cap &= 0x0ffe;
- mtr->flags &= ~METEOR_SINGLE_EVEN;
- if(!(mtr->flags & METEOR_SINGLE_MASK)) {
- mtr->frames_captured++ ;
- wakeup((caddr_t) &read_intr_wait);
- }
+ meteor_reg_t *mtr = (meteor_reg_t *) arg;
+ volatile u_long *cap = (volatile u_long *)mtr->capt_cntrl,
+ *base = (volatile u_long *)mtr->virt_baseaddr,
+ *stat = base + 18; /* mtr->virt_base + 0x48*/
+ 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_intr: pci bus master dma abort: 0x%x 0x%x.\n",
+ *base, *(base+3));
+ pci_conf_write(mtr->tag, PCI_COMMAND_STATUS_REG, pci_err);
+ }
+ if(pci_err & METEOR_TARGET_ABORT) {
+ printf("meteor_intr: pci bus target dma abort: 0x%x 0x%x.\n",
+ *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) {
+ mtr->fifo_errors++ ; /* incrememnt fifo capture errors cnt */
+ printf("meteor: capture error");
+ printf(":%s FIFO overflow.\n", cap_err&0x0100? "even" : "odd");
+ }
+ if (cap_err & 0xc00) {
+ mtr->dma_errors++ ; /* increment DMA capture errors cnt */
+ printf("meteor: capture error");
+ printf(":%s DMA address.\n", cap_err&0x0400? "even" : "odd");
+ }
+ }
+ *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;
+ }
+
+ /*
+ * 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 & PLANER */
+ }
+ }
+ 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 & PLANER */
}
- } else { /* odd field */
- if (mtr->flags & METEOR_SINGLE) {
- *cap &= 0x0ffd;
- mtr->flags &= ~ METEOR_SINGLE_ODD;
- if(!(mtr->flags & METEOR_SINGLE_MASK)) {
- mtr->frames_captured++ ;
- wakeup((caddr_t) &read_intr_wait);
+ }
+
+ /*
+ * If we have a complete frame.
+ */
+ if(!(mtr->flags & METEOR_WANT_MASK)) {
+ mtr->frames_captured++;
+ /*
+ * 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)
+ psignal(mtr->proc, mtr->signal);
+ /*
+ * 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;
}
- } else if (mtr->flags & METEOR_SYNCAP) {
- mm = mtr->mem; /* shared SYNCAP struct */
- /* even field decided to advance or not, we
- simply add stride to that decision */
- *(base+3) = *base + *(base + 6);
- if (mtr->ecurrent != mtr->ocurrent) {
- mm->active |= (1 << (mtr->ocurrent-1));
- mtr->ocurrent = mtr->ecurrent;
- mm->num_active_bufs++;
- if (mtr->proc && mm->signal) {
- mtr->frames_captured++ ;
- psignal(mtr->proc, mm->signal);
+ }
+ /*
+ * 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++;
}
}
}
}
- if (cap_err = (*cap & 0xf00)) {
- if (cap_err & 0x3)
- mtr->fifo_errors++ ; /* incrememnt fifo capture errors cnt */
- if (cap_err & 0xc)
- mtr->dma_errors++ ; /* increment DMA capture errors cnt */
- }
-
- *cap |= 0xf30; /* clear error and field done */
- *status |= 0xf; /* clear interrupt status */
+ *stat |= 0x7; /* clear interrupt status */
return(1);
}
+static void
+set_fps(meteor_reg_t *mtr, u_short fps)
+{
+ volatile u_long *field_mask_even =
+ (volatile u_long *)mtr->virt_baseaddr + 0x4c;
+ volatile u_long *field_mask_odd = field_mask_even + 1;
+ volatile u_long *field_mask_length = field_mask_odd + 1;
+
+ /*
+ * A little sanity checking first...
+ */
+ if(fps < 1) fps = 1;
+ if(fps > 30) fps = 30;
+ mtr->fps = fps;
+ /*
+ * Set the fps using the mask/length.
+ */
+ /* XXX we need some code to actually do this here... */
+}
+
+
/*
* Initialize the capture card to NTSC RGB 16 640x480
*/
@@ -578,6 +779,7 @@ meteor_init ( meteor_reg_t *mtr )
for (i = 0; i < NUM_SAA7196_I2C_REGS; i++) {
SAA7196_WRITE(mtr, i, saa7196_i2c_default[i]);
}
+ set_fps(mtr, 30);
}
@@ -585,10 +787,10 @@ static void met_attach(pcici_t tag, int unit)
{
#ifdef METEOR_IRQ /* from the meteor.h file */
u_long old_irq,new_irq;
-
#endif METEOR_IRQ /* from the meteor.h file */
meteor_reg_t *mtr;
vm_offset_t buf;
+ u_long latency;
if (unit >= NMETEOR) {
printf("meteor_attach: mx%d: invalid unit number\n");
@@ -610,6 +812,24 @@ static void met_attach(pcici_t tag, int unit)
printf("meteor_attach: irq changed from %d to %d\n", (old_irq & 0xff),
(new_irq & 0xff));
#endif METEOR_IRQ
+ /* set latency timer */
+#define PCI_LATENCY_TIMER 0x0c
+#define DEF_LATENCY_VALUE 32 /* is this value ok? */
+ latency = pci_conf_read(tag, PCI_LATENCY_TIMER);
+ latency = (latency >> 8) & 0xff;
+ if(bootverbose) {
+ if(latency)
+ printf("meteor0: PCI bus latency is");
+ else
+ printf("meteor0: PCI bus latency was 0 changing to");
+ }
+ if(!latency) {
+ latency = DEF_LATENCY_VALUE;
+ pci_conf_write(tag, PCI_LATENCY_TIMER, latency<<8);
+ }
+ if(bootverbose) {
+ printf(" %d.\n", latency);
+ }
meteor_init( mtr ); /* set up saa7116 and saa7196 chips */
mtr->tag = tag;
@@ -617,24 +837,28 @@ static void met_attach(pcici_t tag, int unit)
pci_map_int (tag, meteor_intr, (void*) mtr, &net_imask);
/* 640*240*3 round up to nearest pag e*/
- buf = vm_page_alloc_contig(METEOR_ALLOC, 0x100000, 0xffffffff, PAGE_SIZE);
- if (buf == NULL) {
- printf("meteor_attach: big buffer allocation failed\n");
- return;
+ if(METEOR_ALLOC)
+ buf = vm_page_alloc_contig(METEOR_ALLOC,
+ 0x100000, 0xffffffff, PAGE_SIZE);
+ else
+ buf = NULL;
+ if(bootverbose) {
+ printf("meteor0: buffer size %d, addr 0x%x\n", METEOR_ALLOC,
+ buf);
}
+
mtr->bigbuf = buf;
mtr->alloc_pages = METEOR_ALLOC_PAGES;
-
- bzero((caddr_t) buf, METEOR_ALLOC);
-
- buf = vtophys(buf);
- *((volatile u_long *) mtr->virt_baseaddr) = buf;
-
+ if(buf != NULL) {
+ bzero((caddr_t) buf, METEOR_ALLOC);
+ buf = vtophys(buf);
+ *((volatile u_long *) mtr->virt_baseaddr) = buf;
/* 640x480 RGB 16 */
- *((volatile u_long *) mtr->virt_baseaddr + 3) = buf + 0x500;
-
- *((volatile u_long *) mtr->virt_baseaddr + 36) =
- *((volatile u_long *) mtr->virt_baseaddr + 35) = buf + METEOR_ALLOC;
+ *((volatile u_long *) mtr->virt_baseaddr + 3) = buf + 0x500;
+ *((volatile u_long *) mtr->virt_baseaddr + 36) =
+ *((volatile u_long *) mtr->virt_baseaddr + 35) = buf +
+ METEOR_ALLOC;
+ }
mtr->flags = METEOR_INITALIZED | METEOR_NTSC | METEOR_DEV0 |
METEOR_RGB16;
/* 1 frame of 640x480 RGB 16 */
@@ -693,6 +917,10 @@ meteor_open(dev_t dev, int flags, int fmt, struct proc *p)
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);
return(0);
}
@@ -711,47 +939,26 @@ meteor_close(dev_t dev, int flags, int fmt, struct proc *p)
mtr = &(meteor[unit]);
mtr->flags &= ~METEOR_OPEN;
- /* XXX stop any capture modes running */
- switch (mtr->flags & METEOR_CAP_MASK) {
- case METEOR_SINGLE: /* this should not happen, the read capture
+ 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. */
- mtr->flags &= ~(METEOR_SINGLE|METEOR_SINGLE_MASK);
- wakeup((caddr_t) &read_intr_wait); /* continue read */
- break;
+ wakeup((caddr_t)mtr); /* continue read */
+ /*
+ * Turn off capture mode.
+ */
+ *((volatile u_long *) mtr->capt_cntrl) = 0x8ff0;
+ mtr->flags &= ~(METEOR_CAP_MASK|METEOR_WANT_MASK);
- case METEOR_CONTIN: /* continous unsync-ed reading, we can
- simply turn off the capture */
- mtr->flags &= ~METEOR_CONTIN;
- *((volatile u_long *) mtr->capt_cntrl) = 0x0ff0; /* turn off capture */
- break;
- case METEOR_SYNCAP:
- mtr->flags &= ~METEOR_SYNCAP;
- *((volatile u_long *) mtr->capt_cntrl) = 0x0ff0; /* turn off capture */
- mtr->proc = NULL;
- mtr->mem = NULL;
- mtr->ecurrent = mtr->ocurrent = 1;
- /* re-initalize the even/odd DMA positions to top of buffer */
- *((volatile u_long *) mtr->virt_baseaddr) = mtr->bigbuf;
- *((volatile u_long *) mtr->virt_baseaddr +3) =
- *((volatile u_long *) mtr->virt_baseaddr) +
- *((volatile u_long *) mtr->virt_baseaddr+6);
- break;
- case 0:
- break;
- default:
- printf("meteor_close: bad capture state on close %d\n",
- mtr->flags & METEOR_CAP_MASK);
- }
#ifdef METEOR_DEALLOC_PAGES
- if (mtr->bigbuf) {
+ 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 && mtr->alloc_pages > 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),
@@ -760,9 +967,47 @@ meteor_close(dev_t dev, int flags, int fmt, struct proc *p)
}
#endif
#endif
+
return(0);
}
+static void
+start_capture(meteor_reg_t *mtr, unsigned type)
+{
+volatile u_long *cap = (volatile u_long *)mtr->capt_cntrl;
+volatile u_long *p =(volatile u_long *)mtr->virt_baseaddr;
+
+#ifdef RANGE_BUG_FIXED
+#define RANGE_ENABLE 0x8000
+#else
+#define RANGE_ENABLE 0x0000
+#endif
+ 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 | RANGE_ENABLE ;
+ else
+ *cap = 0x0ff1 | RANGE_ENABLE;
+ break;
+ case METEOR_ONLY_ODD_FIELDS:
+ mtr->flags |= METEOR_WANT_ODD;
+ if(type == METEOR_SINGLE)
+ *cap = 0x0ff8 | RANGE_ENABLE;
+ else
+ *cap = 0x0ff2 | RANGE_ENABLE;
+ break;
+ default:
+ mtr->flags |= METEOR_WANT_MASK;
+ if(type == METEOR_SINGLE)
+ *cap = 0x0ffc | RANGE_ENABLE;
+ else
+ *cap = 0x0ff3 | RANGE_ENABLE;
+ break;
+ }
+}
+
int
meteor_read(dev_t dev, struct uio *uio, int ioflag)
{
@@ -776,8 +1021,8 @@ meteor_read(dev_t dev, struct uio *uio, int ioflag)
return(ENXIO);
mtr = &(meteor[unit]);
- if (!mtr->bigbuf) /* no frame buffer allocated (ioctl failed) */
- return(ENXIO);
+ if (mtr->bigbuf == NULL)/* no frame buffer allocated (ioctl failed) */
+ return(ENOMEM);
if (mtr->flags & METEOR_CAP_MASK)
return(EIO); /* already capturing */
@@ -786,18 +1031,17 @@ meteor_read(dev_t dev, struct uio *uio, int ioflag)
if (uio->uio_iov->iov_len < count)
return(EINVAL);
- mtr->flags |= METEOR_SINGLE | METEOR_SINGLE_MASK;
-
- *((volatile u_long *) mtr->capt_cntrl) = 0x0ff3; /* capture */
-
- status = tsleep((caddr_t) &read_intr_wait, METPRI, "capturing", 0);
+ /* 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_read: bad tsleep\n");
- mtr->flags &= ~(METEOR_SINGLE | METEOR_SINGLE_MASK);
+ printf ("meteor_read: tsleep error %d\n", status);
+
+ mtr->flags &= ~(METEOR_SINGLE | METEOR_WANT_MASK);
+
return(status);
}
@@ -831,6 +1075,19 @@ meteor_ioctl(dev_t dev, int cmd, caddr_t arg, int flag, struct proc *pr)
mtr = &(meteor[unit]);
switch (cmd) {
+ 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, 0x0d, SAA7196_REG(mtr, 0x0d) | 0x02);
@@ -897,7 +1154,7 @@ meteor_ioctl(dev_t dev, int cmd, caddr_t arg, int flag, struct proc *pr)
SAA7196_WRITE(mtr, 0x0d,
(SAA7196_REG(mtr, 0x0d) & ~0x01));
SAA7196_WRITE(mtr, 0x0f,
- (SAA7196_REG(mtr, 0x0f) & ~0xc0) | 0x40);
+ (SAA7196_REG(mtr, 0x0f) & ~0xe0) | 0x40);
SAA7196_WRITE(mtr, 0x22, 0x80);
SAA7196_WRITE(mtr, 0x24,
(SAA7196_REG(mtr, 0x24) & ~0x0c) | 0x08);
@@ -911,13 +1168,13 @@ meteor_ioctl(dev_t dev, int cmd, caddr_t arg, int flag, struct proc *pr)
SAA7196_WRITE(mtr, 0x0d,
(SAA7196_REG(mtr, 0x0d) & ~0x01));
SAA7196_WRITE(mtr, 0x0f,
- (SAA7196_REG(mtr, 0x0f) & ~0xc0));
+ (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) | 0x01) ;
+ (SAA7196_REG(mtr, 0x28) & ~0x0c) | 0x04) ;
break;
case METEOR_FMT_SECAM:
mtr->flags = (mtr->flags & ~METEOR_FORM_MASK) |
@@ -931,7 +1188,7 @@ meteor_ioctl(dev_t dev, int cmd, caddr_t arg, int flag, struct proc *pr)
(SAA7196_REG(mtr, 0x24) | 0x0c));
SAA7196_WRITE(mtr, 0x26, 0x20);
SAA7196_WRITE(mtr, 0x28,
- (SAA7196_REG(mtr, 0x28) & ~0x0c) | 0x01) ;
+ (SAA7196_REG(mtr, 0x28) & ~0x0c) | 0x04) ;
break;
case METEOR_FMT_AUTOMODE:
mtr->flags = (mtr->flags & ~METEOR_FORM_MASK) |
@@ -939,7 +1196,7 @@ meteor_ioctl(dev_t dev, int cmd, caddr_t arg, int flag, struct proc *pr)
SAA7196_WRITE(mtr, 0x0d,
(SAA7196_REG(mtr, 0x0d) & ~0x01));
SAA7196_WRITE(mtr, 0x0f,
- (SAA7196_REG(mtr, 0x0f) & ~0xc0) | 0x80);
+ (SAA7196_REG(mtr, 0x0f) & ~0xe0) | 0x80);
break;
default:
return EINVAL;
@@ -949,38 +1206,39 @@ meteor_ioctl(dev_t dev, int cmd, caddr_t arg, int flag, struct proc *pr)
*(u_long *)arg = mtr->flags & METEOR_FORM_MASK;
break;
case METEORCAPTUR:
+ temp = mtr->flags;
switch (*(int *) arg) {
case METEOR_CAP_SINGLE:
- if (!mtr->bigbuf) /* no frame buffer allocated */
- return(ENXIO);
+ if (mtr->bigbuf==NULL) /* no frame buffer allocated */
+ return(ENOMEM);
- if (mtr->flags & METEOR_CAP_MASK)
+ if (temp & METEOR_CAP_MASK)
return(EIO); /* already capturing */
- mtr->flags |= METEOR_SINGLE | METEOR_SINGLE_MASK;
+ start_capture(mtr, METEOR_SINGLE);
- *((volatile u_long *) mtr->capt_cntrl) = 0x0ff3; /* capture */
-
- error = tsleep((caddr_t) &read_intr_wait, METPRI,
- "capturing", 0);
- mtr->flags &= ~(METEOR_SINGLE| METEOR_SINGLE_MASK);
+ /* wait for capture to complete */
+ error=tsleep((caddr_t)mtr, METPRI, "capturing", 0);
+ if(error)
+ printf("meteor_ioctl: tsleep error %d\n",
+ error);
+ mtr->flags &= ~(METEOR_SINGLE|METEOR_WANT_MASK);
break;
case METEOR_CAP_CONTINOUS:
- if (!mtr->bigbuf) /* no frame buffer allocated */
- return(ENXIO);
+ if (mtr->bigbuf==NULL) /* no frame buffer allocated */
+ return(ENOMEM);
- if (mtr->flags & METEOR_CAP_MASK)
+ if (temp & METEOR_CAP_MASK)
return(EIO); /* already capturing */
- mtr->flags |= METEOR_CONTIN;
+ start_capture(mtr, METEOR_CONTIN);
- *((volatile u_long *) mtr->capt_cntrl) = 0x0ff3; /* capture */
break;
case METEOR_CAP_STOP_CONT:
if (mtr->flags & METEOR_CONTIN) {
- mtr->flags &= ~METEOR_CONTIN;
/* turn off capture */
- *((volatile u_long *) mtr->capt_cntrl) = 0x0ff0;
+ *((volatile u_long *) mtr->capt_cntrl) = 0x8ff0;
+ mtr->flags &= ~(METEOR_CONTIN|METEOR_WANT_MASK);
}
break;
@@ -997,22 +1255,21 @@ meteor_ioctl(dev_t dev, int cmd, caddr_t arg, int flag, struct proc *pr)
case METEOR_CAP_N_FRAMES:
if (mtr->flags & METEOR_CAP_MASK)
return(EIO);
- if (mtr->flags & METEOR_YUV_PLANER)
- return(EINVAL);
- if (!mtr->bigbuf)
+ if (mtr->flags & (METEOR_YUV_PLANER | METEOR_YUV_422)) /* XXX*/
+ return(EINVAL); /* should fix intr so we allow these */
+ if (mtr->bigbuf == NULL)
return(ENOMEM);
if ((mtr->frames < 2) ||
(frame->lowat < 1 || frame->lowat >= mtr->frames) ||
- (frame->hiwat < 1 || frame->hiwat >= mtr->frames))
+ (frame->hiwat < 1 || frame->hiwat >= mtr->frames) ||
+ (frame->lowat > frame->hiwat))
return(EINVAL);
- mtr->flags |= METEOR_SYNCAP;
- mtr->proc = pr;
/* meteor_mem structure is on the page after the data */
mem = mtr->mem = (struct meteor_mem *) (mtr->bigbuf +
((mtr->rows*mtr->cols * mtr->depth *
mtr->frames+PAGE_SIZE-1)/PAGE_SIZE)*PAGE_SIZE);
- mtr->ecurrent = mtr->ocurrent = 1;
- mem->signal = frame->signal;
+ mtr->current = 1;
+ mtr->synch_wait = 0;
mem->num_bufs = mtr->frames;
mem->frame_size=
mtr->frame_size = mtr->rows * mtr->cols * mtr->depth;
@@ -1021,233 +1278,328 @@ meteor_ioctl(dev_t dev, int cmd, caddr_t arg, int flag, struct proc *pr)
mem->hiwat = frame->hiwat;
mem->active = 0;
mem->num_active_bufs = 0;
- *((u_long *) mtr->capt_cntrl) = 0x0ff3;
+ /* Start capture */
+ start_capture(mtr, METEOR_SYNCAP);
break;
case METEOR_CAP_STOP_FRAMES:
if (mtr->flags & METEOR_SYNCAP) {
- mtr->flags &= ~METEOR_SYNCAP;
/* turn off capture */
- *((u_long *) mtr->capt_cntrl) = 0x0ff0;
- mtr->proc = NULL;
- mtr->mem = NULL;
- mtr->ecurrent = mtr->ocurrent = 0;
-
- /* re-initalize the even/odd DMA positions to top of buffer*/
- /* XXX if a capture is in progress, this may be trouble */
-
- *((volatile u_long *) mtr->virt_baseaddr) = mtr->bigbuf;
- *((volatile u_long *) mtr->virt_baseaddr +3) =
- *((volatile u_long *) mtr->virt_baseaddr) +
- *((volatile u_long *) mtr->virt_baseaddr+6);
+ *((volatile u_long *) mtr->capt_cntrl) = 0x8ff0;
+ mtr->flags &= ~(METEOR_SYNCAP|METEOR_WANT_MASK);
}
break;
+ case METEOR_HALT_N_FRAMES:
+ if(mtr->flags & METEOR_SYNCAP) {
+ *((volatile u_long *) mtr->capt_cntrl) = 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;
+ break;
case METEORSETGEO:
geo = (struct meteor_geomet *) arg;
- /* can't change parameters while capturing */
+
+ /* 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 ioctl: Geometry odd or even only.\n");
+ 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 ioctl: column too large or not even\n");
+ printf(
+ "meteor ioctl: %d: columns too large or not even.\n",
+ geo->columns);
error = EINVAL;
}
- if ((geo->rows & 0x7fe) != geo->rows) {
- printf("meteor ioctl: rows too large or not even\n");
+ if (((geo->rows & 0x7fe) != geo->rows) ||
+ ((geo->oformat & METEOR_GEO_FIELD_MASK) &&
+ ((geo->rows & 0x3fe) != geo->rows)) ) {
+ printf(
+ "meteor ioctl: %d: rows too large or not even.\n",
+ geo->rows);
error = EINVAL;
}
if (geo->frames > 32) {
- printf("meteor ioctl: frames too large\n");
+ printf("meteor ioctl: too many frames.\n");
error = EINVAL;
}
- if (!error && (temp=geo->rows*geo->columns * geo->frames *2)) {
- if (geo->oformat & METEOR_GEO_RGB24)
- temp = temp * 2;
+ if(error) return error;
+
+ if (temp=geo->rows * geo->columns * geo->frames * 2) {
+ if (geo->oformat & METEOR_GEO_RGB24) temp = temp * 2;
/* meteor_mem structure for SYNC Capture */
- if (geo->frames > 1)
- temp += PAGE_SIZE;
-
- temp = (temp + PAGE_SIZE -1)/PAGE_SIZE;
- if (temp > mtr->alloc_pages) {
- if (mtr->bigbuf)
- kmem_free(kernel_map, mtr->bigbuf,
- (mtr->alloc_pages * PAGE_SIZE));
- mtr->bigbuf = vm_page_alloc_contig((temp*PAGE_SIZE),
- 0x100000, 0xffffffff, PAGE_SIZE);
- mtr->alloc_pages = temp;
- }
- if (mtr->bigbuf) {
- mtr->rows = geo->rows;
- mtr->cols = geo->columns;
- mtr->frames = geo->frames;
- }
- else {
- mtr->alloc_pages = 0;
- printf("meteor_ioctl: buffer allocation failed\n");
- error = ENOMEM;
- }
+ if (geo->frames > 1) temp += PAGE_SIZE;
+
+ temp = (temp + PAGE_SIZE -1)/PAGE_SIZE;
+ if (temp > mtr->alloc_pages) {
+ buf = vm_page_alloc_contig((temp*PAGE_SIZE),
+ 0x100000, 0xffffffff, PAGE_SIZE);
+ if(buf != NULL) {
+ kmem_free(kernel_map, mtr->bigbuf,
+ (mtr->alloc_pages * PAGE_SIZE));
+ mtr->bigbuf = buf;
+ mtr->alloc_pages = temp;
+ printf(
+ "meteor_ioctl: Allocating %d bytes\n", temp*PAGE_SIZE);
+ } else {
+ printf(
+ "meteor_ioctl: couldn't allocate %d byte buffer.\n",
+ temp*PAGE_SIZE);
+ error = ENOMEM;
+ }
+ }
}
+ if(error) return error;
+
+ mtr->rows = geo->rows;
+ mtr->cols = geo->columns;
+ mtr->frames = geo->frames;
p = (volatile u_long *) mtr->virt_baseaddr;
- if (mtr->bigbuf)
- buf = vtophys(mtr->bigbuf);
- else
- buf = 0;
- *p++ = buf; /* even y or even RGB */
- /* set end of buffer location */
- *(p+36) = *(p+35) = buf + mtr->alloc_pages * PAGE_SIZE;
-
- switch (geo->oformat & METEOR_PRO_MASK) {
- case 0: /* default */
- case METEOR_GEO_RGB16:
- mtr->depth = 2;
- if (mtr->flags & METEOR_RGB16 == 0) {
- mtr->flags = (mtr->flags & ~(METEOR_RGB24 |
- METEOR_YUV_PACKED |
- METEOR_YUV_PLANER))
- | METEOR_RGB16;
- }
- if (error == 0) {
- /* recal stride and odd starting point */
+ buf = vtophys(mtr->bigbuf);
+
+ /* set defaults and end of buffer locations */
+ *(p+0) = buf; /* DMA 1 even */
+ *(p+1) = buf; /* DMA 2 even */
+ *(p+2) = buf; /* DMA 3 even */
+ *(p+3) = buf; /* DMA 1 odd */
+ *(p+4) = buf; /* DMA 2 odd */
+ *(p+5) = buf; /* DMA 3 odd */
+ *(p+6) = 0; /* Stride 1 even */
+ *(p+7) = 0; /* Stride 2 even */
+ *(p+8) = 0; /* Stride 3 even */
+ *(p+9) = 0; /* Stride 1 odd */
+ *(p+10) = 0; /* Stride 2 odd */
+ *(p+11) = 0; /* Stride 3 odd */
+ /* set end of DMA location, even/odd */
+#ifdef RANGE_BUG_FIXED
+ *(p+35) = *(p+36) = buf + mtr->alloc_pages * PAGE_SIZE;
+#else
+ /*
+ * There is a bug with the range end on the current
+ * 7116 chip. The 23rd bit is ignored and set to zero
+ * for some reason which makes range checking useless.
+ */
+ *(p+35) = *(p+36) = 0;
+#endif
- *p++ = 0;
- *p++ = 0;
- *p++ = buf + mtr->cols * 2;
- *p++ = 0;
- *p++ = 0;
- /* stride */
- *p = *(p+3) = mtr->cols * 2;
- *(p+6) = *(p+7) = 0xeeeeee01;
- /* set up the saa7196 */
+ switch (geo->oformat & METEOR_GEO_OUTPUT_MASK) {
+ case 0: /* default */
+ case METEOR_GEO_RGB16:
+ mtr->depth = 2;
+ mtr->flags &= ~METEOR_OUTPUT_FMT_MASK;
+ mtr->flags |= METEOR_RGB16;
+ /* recal stride and starting point */
+ switch(mtr->flags & METEOR_ONLY_FIELDS_MASK) {
+ case METEOR_ONLY_ODD_FIELDS:
+ *(p+3) = buf; /*dma 1 o */
+ SAA7196_WRITE(mtr, 0x20, 0xd0);
+ break;
+ case METEOR_ONLY_EVEN_FIELDS:
+ *(p+0) = buf; /*dma 1 e */
+ SAA7196_WRITE(mtr, 0x20, 0xf0);
+ break;
+ default: /* interlaced even/odd */
+ *(p+0) = buf;
+ *(p+3) = buf + mtr->cols * mtr->depth;
+ *(p+6) = *(p+9) = mtr->cols * mtr->depth;
SAA7196_WRITE(mtr, 0x20, 0x90);
+ break;
}
+ *(p+12) = *(p+13) = 0xeeeeee01; /* routes */
break;
- case METEOR_GEO_RGB24:
- mtr->depth = 4;
- if (mtr->flags & METEOR_RGB24 == 0) {
- mtr->flags = (mtr->flags & ~(METEOR_RGB16 |
- METEOR_YUV_PACKED |
- METEOR_YUV_PLANER))
- | METEOR_RGB24;
- }
- if (error == 0 ) {
- /* recal stride and odd starting point */
-
- *p++ = 0;
- *p++ = 0;
- *p++ = buf + mtr->cols * 4;
- /* routes */
- *p++ = 0;
- *p++ = 0;
- /* stride */
- *p = *(p+3) = mtr->cols * 4;
- /* routes */
- *(p+6) = *(p+7) = 0x39393900;
- /* set up the saa7196 */
+ case METEOR_GEO_RGB24:
+ mtr->depth = 4;
+ mtr->flags &= ~METEOR_OUTPUT_FMT_MASK;
+ mtr->flags |= METEOR_RGB24;
+ /* recal stride and starting point */
+ switch(mtr->flags & METEOR_ONLY_FIELDS_MASK) {
+ case METEOR_ONLY_ODD_FIELDS:
+ *(p+3) = buf; /*dma 1 o */
+ SAA7196_WRITE(mtr, 0x20, 0xd2);
+ break;
+ case METEOR_ONLY_EVEN_FIELDS:
+ *(p+0) = buf; /*dma 1 e */
+ SAA7196_WRITE(mtr, 0x20, 0xf2);
+ break;
+ default: /* interlaced even/odd */
+ *(p+0) = buf;
+ *(p+3) = buf + mtr->cols * mtr->depth;
+ *(p+6) = *(p+9) = mtr->cols * mtr->depth;
SAA7196_WRITE(mtr, 0x20, 0x92);
+ break;
}
+ *(p+12) = *(p+13) = 0x39393900; /* routes */
break;
- case METEOR_GEO_YUV_PLANER:
- mtr->depth = 2;
- if (mtr->flags & METEOR_YUV_PLANER == 0) {
- mtr->flags = (mtr->flags & ~(METEOR_RGB16 |
- METEOR_RGB24 |
- METEOR_YUV_PACKED))
- | METEOR_YUV_PLANER;
+ case METEOR_GEO_YUV_PLANER:
+ mtr->depth = 2;
+ mtr->flags &= ~METEOR_OUTPUT_FMT_MASK;
+ mtr->flags |= METEOR_YUV_PLANER;
+ /* recal stride and starting point */
+ temp = mtr->rows * mtr->cols; /* compute frame size */
+ switch(mtr->flags & METEOR_ONLY_FIELDS_MASK) {
+ case METEOR_ONLY_ODD_FIELDS:
+ *(p+3) = buf; /* Y Odd */
+ *(p+4) = buf + temp; /* U Odd */
+ temp >>= 1;
+ *(p+5) = *(p+4) + temp; /* V Odd */
+ SAA7196_WRITE(mtr, 0x20, 0xd1);
+ break;
+ case METEOR_ONLY_EVEN_FIELDS:
+ *(p+0) = buf; /* Y Even */
+ *(p+1) = buf + temp; /* U Even */
+ temp >>= 1;
+ *(p+2) = *(p+1) + temp; /* V Even */
+ SAA7196_WRITE(mtr, 0x20, 0xf1);
+ break;
+ default: /* interlaced even/odd */
+ *(p+0) = buf; /* Y Even */
+ *(p+1) = buf + temp; /* U Even */
+ temp >>= 2;
+ *(p+2) = *(p+1) + temp; /* V Even */
+ *(p+3) = *(p+0) + mtr->cols; /* Y Odd */
+ *(p+4) = *(p+2) + temp; /* U Odd */
+ *(p+5) = *(p+4) + temp; /* V Odd */
+ *(p+6) = *(p+9) = mtr->cols; /* Y Stride */
+ SAA7196_WRITE(mtr, 0x20, 0x91);
+ break;
}
- if (error == 0 ) {
- /* recal stride and odd starting point */
-
- temp = mtr->rows * mtr->cols;
- /* even u */
- *p++ = buf + temp;
- /* even v */
- *p++ = buf + temp + (temp >> 2);
- /* odd y */
- *p++ = buf + mtr->cols;
- /* odd u */
- *p++ = buf + temp + (temp >> 1);
- /* odd v */
- *p++ = buf + temp + (temp >> 1)
- + (temp >> 2);
- /* stride */
- *p = *(p+3) = mtr->cols;
- /* routes */
- *(p+6) = *(p+7) = 0xaaaaffc1;
- /* set up the saa7196 */
+ *(p+12) = *(p+13) = 0xaaaaffc1; /* routes */
+ break;
+ case METEOR_GEO_YUV_422:/* same as planer, different uv order */
+ mtr->depth = 2;
+ mtr->flags &= ~METEOR_OUTPUT_FMT_MASK;
+ mtr->flags |= METEOR_YUV_422;
+ temp = mtr->rows * mtr->cols; /* compute frame size */
+ switch(mtr->flags & METEOR_ONLY_FIELDS_MASK) {
+ case METEOR_ONLY_ODD_FIELDS:
+ *(p+3) = buf;
+ *(p+4) = buf + temp;
+ *(p+5) = *(p+4) + (temp >> 1);
+ SAA7196_WRITE(mtr, 0x20, 0xd1);
+ break;
+ case METEOR_ONLY_EVEN_FIELDS:
+ *(p+0) = buf;
+ *(p+1) = buf + temp;
+ *(p+2) = *(p+1) + (temp >> 1);
+ SAA7196_WRITE(mtr, 0x20, 0xf1);
+ break;
+ default: /* interlaced even/odd */
+ *(p+0) = buf; /* Y even */
+ *(p+1) = buf + temp; /* U even */
+ *(p+2) = *(p+1) + (temp >> 1); /* V even */
+ *(p+3) = *(p+0) + mtr->cols; /* Y odd */
+ temp = mtr->cols >> 1;
+ *(p+4) = *(p+1) + temp; /* U odd */
+ *(p+5) = *(p+2) + temp; /* V odd */
+ *(p+6) = *(p+9) = mtr->cols; /* Y stride */
+ *(p+7) = *(p+10) = temp; /* U stride */
+ *(p+8) = *(p+11) = temp; /* V stride */
SAA7196_WRITE(mtr, 0x20, 0x91);
+ break;
}
+ *(p+12) = *(p+13) = 0xaaaaffc1; /* routes */
break;
- case METEOR_GEO_YUV_PACKED:
- mtr->depth = 2;
- if (mtr->flags & METEOR_YUV_PACKED == 0) {
- mtr->flags = (mtr->flags & ~(METEOR_RGB16 |
- METEOR_RGB24 |
- METEOR_YUV_PLANER))
- | METEOR_YUV_PACKED;
- }
- if (error == 0 ) {
+ case METEOR_GEO_YUV_PACKED:
+ mtr->depth = 2;
+ mtr->flags &= ~METEOR_OUTPUT_FMT_MASK;
+ mtr->flags |= METEOR_YUV_PACKED;
/* recal stride and odd starting point */
-
- *p++ = 0;
- *p++ = 0;
- *p++ = buf + mtr->cols * 2;
- *p++ = 0;
- *p++ = 0;
- /* stride */
- *p = *(p+3) = mtr->cols * 2;
- /* routes */
- *(p+6) = *(p+7) = 0xeeeeee41;
- /* set up the saa7196 */
+ switch(mtr->flags & METEOR_ONLY_FIELDS_MASK) {
+ case METEOR_ONLY_ODD_FIELDS:
+ *(p+3) = buf;
+ SAA7196_WRITE(mtr, 0x20, 0xd1);
+ break;
+ case METEOR_ONLY_EVEN_FIELDS:
+ *(p+0) = buf;
+ SAA7196_WRITE(mtr, 0x20, 0xf1);
+ break;
+ default: /* interlaced even/odd */
+ *(p+0) = buf;
+ *(p+3) = buf + mtr->cols * mtr->depth;
+ *(p+6) = *(p+9) = mtr->cols * mtr->depth;
SAA7196_WRITE(mtr, 0x20, 0x91);
+ break;
}
+ *(p+12) = *(p+13) = 0xeeeeee41; /* routes */
break;
- default:
- error = EINVAL; /* invalid arguement */
+ default:
+ error = EINVAL; /* invalid argument */
printf("meteor_ioctl: invalid output format\n");
break;
}
- if (error == 0 ) {
- /* set cols */
- SAA7196_WRITE(mtr, 0x21, mtr->cols & 0xff);
- SAA7196_WRITE(mtr, 0x24,
+ /* set cols */
+ SAA7196_WRITE(mtr, 0x21, mtr->cols & 0xff);
+ SAA7196_WRITE(mtr, 0x24,
((SAA7196_REG(mtr, 0x24) & ~0x03) |
- ((mtr->cols >> 8) & 0x03)));
- /* set rows */
+ ((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 */
- SAA7196_WRITE(mtr, 0x30,
- (SAA7196_REG(mtr, 0x30) & ~0x10) |
- ((geo->oformat&METEOR_GEO_UNSIGNED)?0:0x10));
+ ((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_PRO_MASK;
+ geo->oformat = (mtr->flags & METEOR_OUTPUT_FMT_MASK) |
+ (mtr->flags & METEOR_ONLY_FIELDS_MASK) |
+ (SAA7196_REG(mtr, 0x30) & 0x10 ?
+ 0:METEOR_GEO_UNSIGNED);
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_ioctl: invalid ioctl request\n");
@@ -1277,10 +1629,11 @@ meteor_mmap(dev_t dev, int offset, int nprot)
if(offset >= mtr->alloc_pages * PAGE_SIZE)
return -1;
- return i386_btop((vtophys(mtr->bigbuf) + offset));
+ return i386_btop(vtophys(mtr->bigbuf) + offset);
}
+#if !defined(METEOR_FreeBSD_210) /* XXX */
static meteor_devsw_installed = 0;
static void meteor_drvinit(void *unused)
@@ -1295,5 +1648,6 @@ static void meteor_drvinit(void *unused)
}
SYSINIT(meteordev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,meteor_drvinit,NULL)
+#endif
#endif /* NMETEOR > 0 */
OpenPOWER on IntegriCloud