| Commit | Line | Data |
|---|---|---|
| 984263bc MD |
1 | /* |
| 2 | * Copyright (c) 1995 Mark Tinguely and Jim Lowe | |
| 3 | * All rights reserved. | |
| 4 | * | |
| 5 | * Redistribution and use in source and binary forms, with or without | |
| 6 | * modification, are permitted provided that the following conditions | |
| 7 | * are met: | |
| 8 | * 1. Redistributions of source code must retain the above copyright | |
| 9 | * notice, this list of conditions and the following disclaimer. | |
| 10 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 11 | * notice, this list of conditions and the following disclaimer in the | |
| 12 | * documentation and/or other materials provided with the distribution. | |
| 13 | * 3. All advertising materials mentioning features or use of this software | |
| 14 | * must display the following acknowledgement: | |
| 15 | * This product includes software developed by Mark Tinguely and Jim Lowe | |
| 16 | * 4. The name of the author may not be used to endorse or promote products | |
| 17 | * derived from this software without specific prior written permission. | |
| 18 | * | |
| 19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
| 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
| 21 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
| 22 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, | |
| 23 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| 24 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
| 25 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
| 27 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | |
| 28 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| 29 | * POSSIBILITY OF SUCH DAMAGE. | |
| 30 | * | |
| 31 | * $FreeBSD: src/sys/pci/meteor.c,v 1.49 1999/09/25 18:24:41 phk Exp $ | |
| 3f625015 | 32 | * $DragonFly: src/sys/dev/video/meteor/meteor.c,v 1.22 2007/05/13 18:33:58 swildner Exp $ |
| 984263bc MD |
33 | */ |
| 34 | ||
| 35 | /* Change History: | |
| 36 | 8/21/95 Release | |
| 37 | 8/23/95 On advice from Stefan Esser, added volatile to PCI | |
| 38 | memory pointers to remove PCI caching . | |
| 39 | 8/29/95 Fixes suggested by Bruce Evans. | |
| 40 | meteor_mmap should return -1 on error rather than 0. | |
| 41 | unit # > NMETEOR should be unit # >= NMETEOR. | |
| 42 | 10/24/95 Turn 50 Hz processing for SECAM and 60 Hz processing | |
| 43 | off for AUTOMODE. | |
| 44 | 11/11/95 Change UV from always begin signed to ioctl selected | |
| 45 | to either signed or unsigned. | |
| 46 | 12/07/95 Changed 7196 startup codes for 50 Hz as recommended | |
| 47 | by Luigi Rizzo (luigi@iet.unipi.it) | |
| 48 | 12/08/95 Clear SECAM bit in PAL/NTSC and set input field count | |
| 49 | bits for 50 Hz mode (PAL/SECAM) before I was setting the | |
| 50 | output count bits. by Luigi Rizzo (luigi@iet.unipi.it) | |
| 51 | 12/18/95 Correct odd DMA field (never exceed, but good for safety | |
| 52 | Changed 7196 startup codes for 50 Hz as recommended | |
| 53 | by Luigi Rizzo (luigi@iet.unipi.it) | |
| 54 | 12/19/95 Changed field toggle mode to enable (offset 0x3c) | |
| 55 | recommended by luigi@iet.unipi.it | |
| 56 | Added in prototyping, include file, staticizing, | |
| 57 | and DEVFS changes from FreeBSD team. | |
| 58 | Changed the default allocated pages from 151 (NTSC) | |
| 59 | to 217 (PAL). | |
| 60 | Cleaned up some old comments in iic_write(). | |
| 61 | Added a Field (even or odd) only capture mode to | |
| 62 | eliminate the high frequency problems with compression | |
| 63 | algorithms. Recommended by luigi@iet.unipi.it. | |
| 64 | Changed geometry ioctl so if it couldn't allocated a | |
| 65 | large enough contiguous space, it wouldn't free the | |
| 66 | stuff it already had. | |
| 67 | Added new mode called YUV_422 which delivers the | |
| 68 | data in planer Y followed by U followed by V. This | |
| 69 | differs from the standard YUV_PACKED mode in that | |
| 70 | the chrominance (UV) data is in the correct (different) | |
| 71 | order. This is for programs like vic and mpeg_encode | |
| 72 | so they don't have to reorder the chrominance data. | |
| 73 | Added field count to stats. | |
| 74 | Increment frame count stat if capturing continuous on | |
| 75 | even frame grabs. | |
| 76 | Added my email address to these comments | |
| 77 | (james@cs.uwm.edu) suggested by (luigi@iet.unipt.it :-). | |
| 78 | Changed the user mode signal mechanism to allow the | |
| 79 | user program to be interrupted at the end of a frame | |
| 80 | in any one of the modes. Added SSIGNAL ioctl. | |
| 81 | Added a SFPS/GFPS ioctl so one may set the frames per | |
| 82 | second that the card catpures. This code needs to be | |
| 83 | completed. | |
| 84 | Changed the interrupt routine so synchronous capture | |
| 85 | will work on fields or frames and the starting frame | |
| 86 | can be either even or odd. | |
| 87 | Added HALT_N_FRAMES and CONT_N_FRAMES so one could | |
| 88 | stop and continue synchronous capture mode. | |
| 89 | Change the tsleep/wakeup function to wait on mtr | |
| 90 | rather than &read_intr_wait. | |
| 91 | 1/22/96 Add option (METEOR_FreeBSD_210) for FreeBSD 2.1 | |
| 92 | to compile. | |
| 93 | Changed intr so it only printed errors every 50 times. | |
| 94 | Added unit number to error messages. | |
| 95 | Added get_meteor_mem and enabled range checking. | |
| 96 | 1/30/96 Added prelim test stuff for direct video dma transfers | |
| 97 | from Amancio Hasty (hasty@rah.star-gate.com). Until | |
| 98 | we get some stuff sorted out, this will be ifdef'ed | |
| 99 | with METEOR_DIRECT_VIDEO. This is very dangerous to | |
| 100 | use at present since we don't check the address that | |
| 101 | is passed by the user!!!!! | |
| 102 | 2/26/96 Added special SVIDEO input device type. | |
| 103 | 2/27/96 Added meteor_reg.h file and associate types Converted | |
| 104 | meteor.c over to using meteor.h file. Prompted by | |
| 105 | Lars Jonas Olsson <ljo@po.cwru.edu>. | |
| 106 | 2/28/96 Added meteor RGB code from Lars Jonas Olsson | |
| 107 | <ljo@po.cwru.edu>. I make some mods to this code, so | |
| 108 | I hope it still works as I don't have an rgb card to | |
| 109 | test with. | |
| 110 | 2/29/96 <ljo@po.cwru.edu> tested the meteor RGB and supplied | |
| 111 | me with diffs. Thanks, we now have a working RGB | |
| 112 | version of the driver. Still need to clean up this | |
| 113 | code. | |
| 114 | 3/1/96 Fixed a nasty little bug that was clearing the VTR | |
| 115 | mode bit when the 7196 status was requested. | |
| 116 | 3/15/96 Fixed bug introduced in previous version that | |
| 117 | stopped the only fields mode from working. | |
| 118 | Added METEOR{GS}TS ioctl, still needs work. | |
| 119 | 3/25/96 Added YUV_9 and YUV_12 modes. Cleaned up some of the | |
| 120 | code and converted variables to use the new register | |
| 121 | types. | |
| 122 | 4/8/96 Fixed the a bug in with the range enable. Pointed | |
| 123 | out by Jim Bray. | |
| 124 | 5/13/96 Fix the FPS ioctl so it actually sets the frames | |
| 125 | per second. Code supplied by ian@robots.ox.ac.uk. | |
| 126 | The new code implements a new define: | |
| 127 | METEOR_SYSTEM_DEFAULT which should be defined as | |
| 128 | METEOR_PAL, METEOR_SECAM, or METEOR_NTSC in your system | |
| 129 | configuration file. If METEOR_SYSTEM_DEFAULT isn't | |
| 130 | defined, and there is not a signal when set_fps is | |
| 131 | called, then the call has no effect. | |
| 132 | Changed the spelling of PLANER to PLANAR as pointed | |
| 133 | out by Paco Hope <paco@cs.virigina.edu> and define | |
| 134 | PLANER to be PLANAR for backward compatibility. | |
| 135 | 5/28/95 METEOR_INPUT_DEV_RCA -> METEOR_INPUT_DEV0, not | |
| 136 | METEOR_GEO_DEV0. Pointed out by Ian Reid, | |
| 137 | <ian@robots.ox.ac.uk>. | |
| 138 | METEOR_DEV_MASK should be 0x0000f000 and not | |
| 139 | 0x2000f000, otherwise METEOR_RGB gets masked | |
| 140 | out. Pointed out by Ian Reid. | |
| 141 | Changed the fps code to give even distribution for | |
| 142 | low frame rates. Code supplied by Ian Reid. | |
| 143 | Fix some problems with the RGB version. Patch supplied | |
| 144 | by <ljo@po.cwru.edu>. | |
| 145 | Added METEOR_FIELD_MODE to include files for a | |
| 146 | future version of this driver. | |
| 147 | */ | |
| 148 | ||
| 1f2de5d4 | 149 | #include "use_meteor.h" |
| 984263bc MD |
150 | #include "opt_meteor.h" |
| 151 | ||
| 152 | #include <sys/param.h> | |
| 153 | #include <sys/systm.h> | |
| 154 | #include <sys/conf.h> | |
| fef8985e | 155 | #include <sys/device.h> |
| 984263bc MD |
156 | #include <sys/kernel.h> |
| 157 | #include <sys/signalvar.h> | |
| 158 | #include <sys/mman.h> | |
| 159 | #include <sys/uio.h> | |
| 160 | ||
| 161 | #if defined(METEOR_FreeBSD_210) | |
| 162 | #include <machine/cpu.h> /* bootverbose */ | |
| 163 | #endif | |
| 164 | ||
| 165 | #include <vm/vm.h> | |
| 166 | #include <vm/vm_kern.h> | |
| 167 | #include <vm/pmap.h> | |
| 168 | #include <vm/vm_extern.h> | |
| 169 | ||
| 1f2de5d4 MD |
170 | #include <bus/pci/pcivar.h> |
| 171 | #include <bus/pci/pcireg.h> | |
| a35cc233 JS |
172 | #include <dev/video/meteor/ioctl_meteor.h> |
| 173 | #include <dev/video/meteor/meteor_reg.h> | |
| 984263bc MD |
174 | |
| 175 | ||
| 5ca58d54 | 176 | static void meteor_intr (void *arg); |
| 984263bc MD |
177 | |
| 178 | /* | |
| 179 | * Allocate enough memory for: | |
| 180 | * 768x576 RGB 16 or YUV (16 storage bits/pixel) = 884736 = 216 pages | |
| 181 | * | |
| 182 | * You may override this using the options "METEOR_ALLOC_PAGES=value" in your | |
| 183 | * kernel configuration file. | |
| 184 | */ | |
| 185 | #ifndef METEOR_ALLOC_PAGES | |
| 186 | #define METEOR_ALLOC_PAGES 217 | |
| 187 | #endif | |
| 188 | #define METEOR_ALLOC (METEOR_ALLOC_PAGES * PAGE_SIZE) | |
| 189 | ||
| 190 | static meteor_reg_t meteor[NMETEOR]; | |
| 191 | #define METEOR_NUM(mtr) ((mtr - &meteor[0])/sizeof(meteor_reg_t)) | |
| 192 | ||
| 377d4740 | 193 | #define METPRI PCATCH |
| 984263bc MD |
194 | |
| 195 | static const char* met_probe (pcici_t tag, pcidi_t type); | |
| 196 | static void met_attach(pcici_t tag, int unit); | |
| 197 | static u_long met_count; | |
| 198 | ||
| 199 | static struct pci_device met_device = { | |
| 200 | "meteor", | |
| 201 | met_probe, | |
| 202 | met_attach, | |
| 203 | &met_count | |
| 204 | }; | |
| 205 | ||
| 206 | COMPAT_PCI_DRIVER (meteor, met_device); | |
| 207 | ||
| 208 | #if defined(METEOR_FreeBSD_210) /* XXX */ | |
| 209 | d_open_t meteor_open; | |
| 210 | d_close_t meteor_close; | |
| 211 | d_read_t meteor_read; | |
| 212 | d_write_t meteor_write; | |
| 213 | d_ioctl_t meteor_ioctl; | |
| 214 | d_mmap_t meteor_mmap; | |
| 215 | #else | |
| 216 | static d_open_t meteor_open; | |
| 217 | static d_close_t meteor_close; | |
| 218 | static d_read_t meteor_read; | |
| 219 | static d_write_t meteor_write; | |
| 220 | static d_ioctl_t meteor_ioctl; | |
| 221 | static d_mmap_t meteor_mmap; | |
| 222 | ||
| 223 | #define CDEV_MAJOR 67 | |
| fef8985e MD |
224 | static struct dev_ops meteor_ops = { |
| 225 | { "meteor", CDEV_MAJOR, 0 }, | |
| 226 | .d_open = meteor_open, | |
| 227 | .d_close = meteor_close, | |
| 228 | .d_read = meteor_read, | |
| 229 | .d_write = meteor_write, | |
| 230 | .d_ioctl = meteor_ioctl, | |
| 231 | .d_mmap = meteor_mmap, | |
| 984263bc MD |
232 | }; |
| 233 | #endif | |
| 234 | ||
| 235 | static mreg_t saa7116_pci_default[sizeof(struct saa7116_regs)/sizeof(mreg_t)]={ | |
| 236 | /* PCI Memory registers */ | |
| 237 | /* BITS Type Description */ | |
| 238 | /* 0x00 */ 0x00000000, /* 31:1 e*RW DMA 1 (Even) | |
| 239 | 0 RO 0x0 */ | |
| 240 | /* 0x04 */ 0x00000000, /* 31:2 e*RW DMA 2 (Even) | |
| 241 | 1:0 RO 0x0 */ | |
| 242 | /* 0x08 */ 0x00000000, /* 31:2 e*RW DMA 3 (Even) | |
| 243 | 1:0 RO 0x0 */ | |
| 244 | /* 0x0c */ 0x00000000, /* 31:1 o*RW DMA 1 (Odd) | |
| 245 | 0 RO 0x0 */ | |
| 246 | /* 0x10 */ 0x00000000, /* 31:2 o*RW DMA 2 (Odd) | |
| 247 | 1:0 RO 0x0 */ | |
| 248 | /* 0x14 */ 0x00000000, /* 31:2 o*RW DMA 3 (Odd) | |
| 249 | 1:0 RO 0x0 */ | |
| 250 | /* 0x18 */ 0x00000500, /* 15:2 e*RW Stride 1 (Even) | |
| 251 | 1:0 RO 0x0 */ | |
| 252 | /* 0x1c */ 0x00000000, /* 15:2 e*RW Stride 2 (Even) | |
| 253 | 1:0 RO 0x0 */ | |
| 254 | /* 0x20 */ 0x00000000, /* 15:2 e*RW Stride 3 (Even) | |
| 255 | 1:0 RO 0x0 */ | |
| 256 | /* 0x24 */ 0x00000500, /* 15:2 o*RW Stride 1 (Odd) | |
| 257 | 1:0 RO 0x0 */ | |
| 258 | /* 0x28 */ 0x00000000, /* 15:2 o*RW Stride 2 (Odd) | |
| 259 | 1:0 RO 0x0 */ | |
| 260 | /* 0x2c */ 0x00000000, /* 15:2 o*RW Stride 3 (Odd) | |
| 261 | 1:0 RO 0x0 */ | |
| 262 | /* 0x30 */ 0xeeeeee01, /* 31:8 *RW Route (Even) | |
| 263 | 7:0 *RW Mode (Even) */ | |
| 264 | /* 0x34 */ 0xeeeeee01, /* 31:8 *RW Route (Odd) | |
| 265 | 7:0 *RW Mode (Odd) */ | |
| 266 | /* 0x38 */ 0x00200020, /* 22:16 *RW FIFO Trigger Planer Mode, | |
| 267 | 6:0 *RW FIFO Trigger Packed Mode */ | |
| 268 | /* 0x3c */ 0x00000107, /* 9:8 *RW Reserved (0x0) | |
| 269 | 2 *RW Field Toggle | |
| 270 | 1 *RW Reserved (0x1) | |
| 271 | 0 *RW Reserved (0x1) */ | |
| 272 | /* 0x40 */ 0x000000c0, /* 15 *RW Range Enable | |
| 273 | 14 *RW Corrupt Disable | |
| 274 | 11 *RR Address Error (Odd) | |
| 275 | 10 *RR Address Error (Even) | |
| 276 | 9 *RR Field Corrupt (Odd) | |
| 277 | 8 *RR Field Corrupt (Even) | |
| 278 | 7 *RW Fifo Enable | |
| 279 | 6 *RW VRSTN# | |
| 280 | 5 *RR Field Done (Odd) | |
| 281 | 4 *RR Field Done (Even) | |
| 282 | 3 *RS Single Field Capture (Odd) | |
| 283 | 2 *RS Single Field Capture (Even) | |
| 284 | 1 *RW Capture (ODD) Continous | |
| 285 | 0 *RW Capture (Even) Continous */ | |
| 286 | /* 0x44 */ 0x00000000, /* 7:0 *RW Retry Wait Counter */ | |
| 287 | /* 0x48 */ 0x00000307, /* 10 *RW Interrupt mask, start of field | |
| 288 | 9 *RW Interrupt mask, end odd field | |
| 289 | 8 *RW Interrupt mask, end even field | |
| 290 | 2 *RR Interrupt status, start of field | |
| 291 | 1 *RR Interrupt status, end of odd | |
| 292 | 0 *RR Interrupt status, end of even */ | |
| 293 | /* 0x4c */ 0x00000001, /* 31:0 *RW Field Mask (Even) continous */ | |
| 294 | /* 0x50 */ 0x00000001, /* 31:0 *RW Field Mask (Odd) continous */ | |
| 295 | /* 0x54 */ 0x00000000, /* 20:16 *RW Mask Length (Odd) | |
| 296 | 4:0 *RW Mask Length (Even) */ | |
| 297 | /* 0x58 */ 0x0005007c, /* 22:16 *RW FIFO almost empty | |
| 298 | 6:0 *RW FIFO almost full */ | |
| 299 | /* 0x5c */ 0x461e1e0f, /* 31:24 *RW I2C Phase 4 | |
| 300 | 23:16 *RW I2C Phase 3 | |
| 301 | 15:8 *RW I2C Phase 2 | |
| 302 | 7:0 *RW I2C Phase 1 */ | |
| 303 | /* 0x60 */ 0x00000300, /* 31:24 *RO I2C Read Data | |
| 304 | 23:16 **RW I2C Auto Address | |
| 305 | 11 RO I2C SCL Input | |
| 306 | 10 RO I2C SDA Input | |
| 307 | 9 RR I2C Direct Abort | |
| 308 | 8 RR I2C Auto Abort | |
| 309 | 3 RW I2C SCL Output | |
| 310 | 2 RW I2C SDA Output | |
| 311 | 1 RW I2C Bypass | |
| 312 | 0 RW I2C Auto Enable */ | |
| 313 | /* 0x64 */ 0x00000000, /* 24 RS I2C New Cycle | |
| 314 | 23:16 **RW I2C Direct Address | |
| 315 | 15:8 **RW I2C Direct Sub-address | |
| 316 | 7:0 **RW I2C Direct Write Address */ | |
| 317 | /* 0x68 */ 0x00000000, /* 31:24 **RW I2C Auto Sub-address 1 (Even) | |
| 318 | 23:16 **RW I2C Auto Data 1 (Even) | |
| 319 | 15:8 **RW I2C Auto Sub-address 0 (Even) | |
| 320 | 7:0 **RW I2C Auto Data 0 (Even) */ | |
| 321 | /* 0x6c */ 0x00000000, /* 31:24 **RW I2C Auto Sub-address 3 (Even) | |
| 322 | 23:16 **RW I2C Auto Data 3 (Even) | |
| 323 | 15:8 **RW I2C Auto Sub-address 2 (Even) | |
| 324 | 7:0 **RW I2C Auto Data 2 (Even) */ | |
| 325 | /* 0x70 */ 0x00000000, /* 31:24 **RW I2C Auto Sub-address 5 (Even) | |
| 326 | 23:16 **RW I2C Auto Data 5 (Even) | |
| 327 | 15:8 **RW I2C Auto Sub-address 4 (Even) | |
| 328 | 7:0 **RW I2C Auto Data 4 (Even) */ | |
| 329 | /* 0x74 */ 0x00000000, /* 31:24 **RW I2C Auto Sub-address 7 (Even) | |
| 330 | 23:16 **RW I2C Auto Data 7 (Even) | |
| 331 | 15:8 **RW I2C Auto Sub-address 6 (Even) | |
| 332 | 7:0 **RW I2C Auto Data 6 (Even) */ | |
| 333 | /* 0x78 */ 0x00000000, /* 31:24 **RW I2C Auto Sub-address 1 (Odd) | |
| 334 | 23:16 **RW I2C Auto Data 1 (Odd) | |
| 335 | 15:8 **RW I2C Auto Sub-address 0 (Odd) | |
| 336 | 7:0 **RW I2C Auto Data 0 (Odd) */ | |
| 337 | /* 0x7c */ 0x00000000, /* 31:24 **RW I2C Auto Sub-address 3 (Odd) | |
| 338 | 23:16 **RW I2C Auto Data 3 (Odd) | |
| 339 | 15:8 **RW I2C Auto Sub-address 2 (Odd) | |
| 340 | 7:0 **RW I2C Auto Data 2 (Odd) */ | |
| 341 | /* 0x80 */ 0x00000000, /* 31:24 **RW I2C Auto Sub-address 5 (Odd) | |
| 342 | 23:16 **RW I2C Auto Data 5 (Odd) | |
| 343 | 15:8 **RW I2C Auto Sub-address 4 (Odd) | |
| 344 | 7:0 **RW I2C Auto Data 4 (Odd) */ | |
| 345 | /* 0x84 */ 0x00000000, /* 31:24 **RW I2C Auto Sub-address 7 (Odd) | |
| 346 | 23:16 **RW I2C Auto Data 7 (Odd) | |
| 347 | 15:8 **RW I2C Auto Sub-address 6 (Odd) | |
| 348 | 7:0 **RW I2C Auto Data 6 (Odd) */ | |
| 349 | /* 0x88 */ 0x00000000, /* 23:16 **RW I2C Register Enable (Odd) | |
| 350 | 7:0 **RW I2C Register Enable (Even) */ | |
| 351 | /* 0x8c */ 0x00000000, /* 23:2 e*RW DMA End (Even) | |
| 352 | 1:0 RO 0x0 */ | |
| 353 | /* 0x90 */ 0x00000000 /* 23:2 e*RW DMA End (Odd) | |
| 354 | 1:0 RO 0x0 */ | |
| 355 | }; | |
| 356 | ||
| 357 | static u_char saa7196_i2c_default[NUM_SAA7196_I2C_REGS] = { | |
| 358 | /* SAA7196 I2C bus control */ | |
| 359 | /* BITS Function */ | |
| 360 | /* 00 */ 0x50, /* 7:0 Increment Delay */ | |
| 361 | /* 01 */ 0x30, /* 7:0 Horizontal Sync Begin for 50hz */ | |
| 362 | /* 02 */ 0x00, /* 7:0 Horizontal Sync Stop for 50hz */ | |
| 363 | /* 03 */ 0xe8, /* 7:0 Horizontal Sync Clamp Start for 50hz */ | |
| 364 | /* 04 */ 0xb6, /* 7:0 Horizontal Sync Clamp Stop for 50hz */ | |
| 365 | /* 05 */ 0xf4, /* 7:0 Horizontal Sync Start after PH1 for 50hz */ | |
| 366 | /* 06 */ 0x46, /* 7 Input mode =0 CVBS, =1 S-Video | |
| 367 | 6 Pre filter | |
| 368 | 5:4 Aperture Bandpass characteristics | |
| 369 | 3:2 Coring range for high freq | |
| 370 | 1:0 Aperture bandpass filter weights */ | |
| 371 | /* 07 */ 0x00, /* 7:0 Hue */ | |
| 372 | /* 08 */ 0x7f, /* 7:3 Colour-killer threshold QAM (PAL, NTSC) */ | |
| 373 | /* 09 */ 0x7f, /* 7:3 Colour-killer threshold SECAM */ | |
| 374 | /* 0a */ 0x7f, /* 7:0 PAL switch sensitivity */ | |
| 375 | /* 0b */ 0x7f, /* 7:0 SECAM switch sensitivity */ | |
| 376 | /* 0c */ 0x40, /* 7 Colour-on bit | |
| 377 | 6:5 AGC filter */ | |
| 378 | /* 0d */ 0x84, /* 7 VTR/TV mode bit = 1->VTR mode | |
| 379 | 3 Realtime output mode select bit | |
| 380 | 2 HREF position select | |
| 381 | 1 Status byte select | |
| 382 | 0 SECAM mode bit */ | |
| 383 | /* 0e */ 0x38, /* 7 Horizontal clock PLL | |
| 384 | 5 Select interal/external clock source | |
| 385 | 4 Output enable of Horizontal/Vertical sync | |
| 386 | 3 Data output YUV enable | |
| 387 | 2 S-VHS bit | |
| 388 | 1 GPSW2 | |
| 389 | 0 GPSW1 */ | |
| 390 | /* 0f */ 0x50, /* 7 Automatic Field detection | |
| 391 | 6 Field Select 0 = 50hz, 1=60hz | |
| 392 | 5 SECAM cross-colour reduction | |
| 393 | 4 Enable sync and clamping pulse | |
| 394 | 3:1 Luminance delay compensation */ | |
| 395 | /* 10 */ 0x00, /* 2 Select HREF Position | |
| 396 | 1:0 Vertical noise reduction */ | |
| 397 | /* 11 */ 0x2c, /* 7:0 Chrominance gain conrtol for QAM */ | |
| 398 | /* 12 */ 0x40, /* 7:0 Chrominance saturation control for VRAM port */ | |
| 399 | /* 13 */ 0x40, /* 7:0 Luminance contract control for VRAM port */ | |
| 400 | /* 14 */ 0x34, /* 7:0 Horizontal sync begin for 60hz */ | |
| 401 | #ifdef notdef | |
| 402 | /* 15 */ 0x0c, /* 7:0 Horizontal sync stop for 60hz */ | |
| 403 | /* 16 */ 0xfb, /* 7:0 Horizontal clamp begin for 60hz */ | |
| 404 | /* 17 */ 0xd4, /* 7:0 Horizontal clamp stop for 60hz */ | |
| 405 | /* 18 */ 0xec, /* 7:0 Horizontal sync start after PH1 for 60hz */ | |
| 406 | #else | |
| 407 | 0x0a, 0xf4, 0xce, 0xf4, | |
| 408 | #endif | |
| 409 | /* 19 */ 0x80, /* 7:0 Luminance brightness control for VRAM port */ | |
| 410 | /* 1a */ 0x00, | |
| 411 | /* 1b */ 0x00, | |
| 412 | /* 1c */ 0x00, | |
| 413 | /* 1d */ 0x00, | |
| 414 | /* 1e */ 0x00, | |
| 415 | /* 1f */ 0x00, | |
| 416 | /* 20 */ 0x90, /* 7 ROM table bypass switch | |
| 417 | 6:5 Set output field mode | |
| 418 | 4 VRAM port outputs enable | |
| 419 | 3:2 First pixel position in VRO data | |
| 420 | 1:0 FIFO output register select */ | |
| 421 | /* 21 */ 0x80, /* 7:0 [7:0] Pixel number per line on output */ | |
| 422 | /* 22 */ 0x80, /* 7:0 [7:0] Pixel number per line on input */ | |
| 423 | /* 23 */ 0x03, /* 7:0 [7:0] Horizontal start position of scaling win*/ | |
| 424 | /* 24 */ 0x8a, /* 7:5 Horizontal decimation filter | |
| 425 | 4 [8] Horizontal start position of scaling win | |
| 426 | 3:2 [9:8] Pixel number per line on input | |
| 427 | 1:0 [9:8] Pixel number per line on output */ | |
| 428 | /* 25 */ 0xf0, /* 7:0 [7:0] Line number per output field */ | |
| 429 | /* 26 */ 0xf0, /* 7:0 [7:0] Line number per input field */ | |
| 430 | /* 27 */ 0x0f, /* 7:0 [7:0] Vertical start of scaling window */ | |
| 431 | /* 28 */ 0x80, /* 7 Adaptive filter switch | |
| 432 | 6:5 Vertical luminance data processing | |
| 433 | 4 [8] Vertical start of scaling window | |
| 434 | 3:2 [9:8] Line number per input field | |
| 435 | 1:0 [9:8] Line number per output field */ | |
| 436 | /* 29 */ 0x16, /* 7:0 [7:0] Vertical bypass start */ | |
| 437 | /* 2a */ 0x00, /* 7:0 [7:0] Vertical bypass count */ | |
| 438 | /* 2b */ 0x00, /* 4 [8] Vertical bypass start | |
| 439 | 2 [8] Vertical bypass count | |
| 440 | 0 Polarity, internally detected odd even flag */ | |
| 441 | /* 2c */ 0x80, /* 7:0 Set lower limit V for colour-keying */ | |
| 442 | /* 2d */ 0x7f, /* 7:0 Set upper limit V for colour-keying */ | |
| 443 | /* 2e */ 0x80, /* 7:0 Set lower limit U for colour-keying */ | |
| 444 | /* 2f */ 0x7f, /* 7:0 Set upper limit U for colour-keying */ | |
| 445 | /* 30 */ 0xbf /* 7 VRAM bus output format | |
| 446 | 6 Adaptive geometrical filter | |
| 447 | 5 Luminance limiting value | |
| 448 | 4 Monochrome and two's complement output data sel | |
| 449 | 3 Line quailifier flag | |
| 450 | 2 Pixel qualifier flag | |
| 451 | 1 Transparent data transfer | |
| 452 | 0 Extended formats enable bit */ | |
| 453 | }; | |
| 454 | ||
| 455 | static u_char bt254_default[NUM_BT254_REGS] = { | |
| 456 | 0x00, /* 24 bpp */ | |
| 457 | 0xa0, | |
| 458 | 0xa0, | |
| 459 | 0xa0, | |
| 460 | 0x50, | |
| 461 | 0x50, | |
| 462 | 0x50, | |
| 463 | } ; | |
| 464 | ||
| 465 | /* | |
| 466 | * i2c_write: | |
| 467 | * Returns 0 Succesful completion. | |
| 468 | * Returns 1 If transfer aborted or timeout occured. | |
| 469 | * | |
| 470 | */ | |
| 471 | static int i2c_print_err = 1; | |
| 472 | static int | |
| 473 | i2c_write(meteor_reg_t * mtr, u_char slave, u_char rw, u_char reg, u_char data) | |
| 474 | { | |
| 3d0f5f54 RG |
475 | unsigned long wait_counter = 0x0001ffff; |
| 476 | mreg_t * iic_write_loc = &mtr->base->i2c_write; | |
| 477 | int err = 0; | |
| 984263bc MD |
478 | |
| 479 | ||
| 480 | /* Write the data the the i2c write register */ | |
| 481 | *iic_write_loc = SAA7116_IIC_NEW_CYCLE | | |
| 482 | (((u_long)slave|(u_long)rw) << 16) | | |
| 483 | ((u_long)reg << 8) | (u_long)data; | |
| 484 | ||
| 485 | /* Wait until the i2c cycle is compeleted */ | |
| 486 | while((*iic_write_loc & SAA7116_IIC_NEW_CYCLE)) { | |
| 487 | if(!wait_counter) break; | |
| 488 | wait_counter--; | |
| 489 | } | |
| 490 | ||
| 491 | /* 1ffff should be enough delay time for the i2c cycle to complete */ | |
| 492 | if(!wait_counter) { | |
| 493 | if(i2c_print_err) | |
| e3869ec7 | 494 | kprintf("meteor%d: %d i2c %s transfer timeout 0x%x", |
| 984263bc MD |
495 | METEOR_NUM(mtr), slave, |
| 496 | rw ? "read" : "write", *iic_write_loc); | |
| 497 | ||
| 498 | err=1; | |
| 499 | } | |
| 500 | ||
| 501 | /* Check for error on direct write, clear if any */ | |
| 502 | if(mtr->base->i2c_read & SAA7116_IIC_DIRECT_TRANSFER_ABORTED){ | |
| 503 | mtr->base->i2c_read |= SAA7116_IIC_DIRECT_TRANSFER_ABORTED; | |
| 504 | if(i2c_print_err) | |
| 3f625015 | 505 | kprintf("meteor%d: 0x%x i2c %s transfer aborted", |
| 984263bc MD |
506 | METEOR_NUM(mtr), slave, |
| 507 | rw ? "read" : "write" ); | |
| 508 | err= 1; | |
| 509 | } | |
| 510 | ||
| 511 | if(err) { | |
| 512 | if(i2c_print_err) | |
| e3869ec7 | 513 | kprintf(" - reg=0x%x, value=0x%x.\n", reg, data); |
| 984263bc MD |
514 | } |
| 515 | ||
| 516 | return err; | |
| 517 | } | |
| 518 | #undef i2c_print | |
| 519 | ||
| 520 | static const char * | |
| 521 | met_probe (pcici_t tag, pcidi_t type) | |
| 522 | { | |
| 984263bc MD |
523 | switch (type) { |
| 524 | case SAA7116_PHILIPS_ID: /* meteor */ | |
| 525 | return("Philips SAA 7116"); | |
| 526 | }; | |
| 60233e58 | 527 | return (NULL); |
| 984263bc MD |
528 | } |
| 529 | ||
| 530 | /* interrupt handling routine | |
| 531 | complete meteor_read() if using interrupts | |
| 532 | */ | |
| 533 | static void | |
| 534 | meteor_intr(void *arg) | |
| 535 | { | |
| 536 | meteor_reg_t *mtr = (meteor_reg_t *) arg; | |
| 537 | mreg_t *cap = &mtr->base->cap_cntl, | |
| 538 | *base = &mtr->base->dma1e, | |
| 539 | *stat = &mtr->base->irq_stat; | |
| 540 | u_long status = *stat, | |
| 541 | cap_err = *cap & 0x00000f00, | |
| 542 | #ifdef METEOR_CHECK_PCI_BUS | |
| 543 | pci_err = pci_conf_read(mtr->tag, | |
| 544 | PCI_COMMAND_STATUS_REG), | |
| 545 | #endif | |
| 546 | next_base = (u_long)(vtophys(mtr->bigbuf)); | |
| 547 | ||
| 548 | /* | |
| 549 | * Disable future interrupts if a capture mode is not selected. | |
| 550 | * This can happen when we are in the process of closing or | |
| 551 | * changing capture modes, otherwise it shouldn't happen. | |
| 552 | */ | |
| 553 | if(!(mtr->flags & METEOR_CAP_MASK)) { | |
| 554 | *cap &= 0x8ff0; /* disable future interrupts */ | |
| 555 | } | |
| 556 | #ifdef METEOR_CHECK_PCI_BUS | |
| 557 | /* | |
| 558 | * Check for pci bus errors. | |
| 559 | */ | |
| 560 | #define METEOR_MASTER_ABORT 0x20000000 | |
| 561 | #define METEOR_TARGET_ABORT 0x10000000 | |
| 562 | if(pci_err & METEOR_MASTER_ABORT) { | |
| e3869ec7 | 563 | kprintf("meteor%d: intr: pci bus master dma abort: 0x%x 0x%x.\n", |
| 984263bc MD |
564 | METEOR_NUM(mtr), *base, *(base+3)); |
| 565 | pci_conf_write(mtr->tag, PCI_COMMAND_STATUS_REG, pci_err); | |
| 566 | } | |
| 567 | if(pci_err & METEOR_TARGET_ABORT) { | |
| e3869ec7 | 568 | kprintf("meteor%d: intr: pci bus target dma abort: 0x%x 0x%x.\n", |
| 984263bc MD |
569 | METEOR_NUM(mtr), *base, *(base+3)); |
| 570 | pci_conf_write(mtr->tag, PCI_COMMAND_STATUS_REG, pci_err); | |
| 571 | } | |
| 572 | #endif | |
| 573 | /* | |
| 574 | * Check for errors. | |
| 575 | */ | |
| 576 | if (cap_err) { | |
| 577 | if (cap_err & 0x300) { | |
| 578 | if(mtr->fifo_errors % 50 == 0) { | |
| e3869ec7 SW |
579 | kprintf("meteor%d: capture error", METEOR_NUM(mtr)); |
| 580 | kprintf(": %s FIFO overflow.\n", | |
| 984263bc MD |
581 | cap_err&0x0100? "even" : "odd"); |
| 582 | } | |
| 583 | mtr->fifo_errors++ ; /* increment fifo capture errors cnt */ | |
| 584 | } | |
| 585 | if (cap_err & 0xc00) { | |
| 586 | if(mtr->dma_errors % 50 == 0) { | |
| e3869ec7 SW |
587 | kprintf("meteor%d: capture error", METEOR_NUM(mtr)); |
| 588 | kprintf(": %s DMA address.\n", | |
| 984263bc MD |
589 | cap_err&0x0400? "even" : "odd"); |
| 590 | } | |
| 591 | mtr->dma_errors++ ; /* increment DMA capture errors cnt */ | |
| 592 | } | |
| 593 | } | |
| 594 | *cap |= 0x0f30; /* clear error and field done */ | |
| 595 | ||
| 596 | /* | |
| 597 | * In synchronous capture mode we need to know what the address | |
| 598 | * offset for the next field/frame will be. next_base holds the | |
| 599 | * value for the even dma buffers (for odd, one must add stride). | |
| 600 | */ | |
| 601 | if((mtr->flags & METEOR_SYNCAP) && !mtr->synch_wait && | |
| 602 | (mtr->current < mtr->frames)) { /* could be !=, but < is safer */ | |
| 603 | /* next_base is initialized to mtr->bigbuf */ | |
| 604 | next_base += mtr->frame_size * mtr->current; | |
| 605 | if(mtr->flags & METEOR_WANT_TS) | |
| 606 | next_base += sizeof(struct timeval) * mtr->current; | |
| 607 | } | |
| 608 | ||
| 609 | /* | |
| 610 | * Count the field and clear the field flag. | |
| 611 | * | |
| 612 | * In single mode capture, clear the continuous capture mode. | |
| 613 | * | |
| 614 | * In synchronous capture mode, if we have room for another field, | |
| 615 | * adjust DMA buffer pointers. | |
| 616 | * When we are above the hi water mark (hiwat), mtr->synch_wait will | |
| 617 | * be set and we will not bump the DMA buffer pointers. Thus, once | |
| 618 | * we reach the hi water mark, the driver acts like a continuous mode | |
| 619 | * capture on the mtr->current frame until we hit the low water | |
| 620 | * mark (lowat). The user had the option of stopping or halting | |
| 621 | * the capture if this is not the desired effect. | |
| 622 | */ | |
| 623 | if (status & 0x1) { /* even field */ | |
| 624 | mtr->even_fields_captured++; | |
| 625 | mtr->flags &= ~METEOR_WANT_EVEN; | |
| 626 | if((mtr->flags & METEOR_SYNCAP) && !mtr->synch_wait) { | |
| 627 | *base = next_base; | |
| 628 | /* XXX should add adjustments for YUV_422 & PLANAR */ | |
| 629 | } | |
| 630 | /* | |
| 631 | * If the user requested to be notified via signal, | |
| 632 | * let them know the field is complete. | |
| 633 | */ | |
| 634 | if(mtr->proc && (mtr->signal & METEOR_SIG_MODE_MASK)) | |
| 84204577 | 635 | ksignal(mtr->proc, mtr->signal&(~METEOR_SIG_MODE_MASK)); |
| 984263bc MD |
636 | } |
| 637 | if (status & 0x2) { /* odd field */ | |
| 638 | mtr->odd_fields_captured++; | |
| 639 | mtr->flags &= ~METEOR_WANT_ODD; | |
| 640 | if((mtr->flags & METEOR_SYNCAP) && !mtr->synch_wait) { | |
| 641 | *(base+3) = next_base + *(base+6); | |
| 642 | /* XXX should add adjustments for YUV_422 & PLANAR */ | |
| 643 | } | |
| 644 | /* | |
| 645 | * If the user requested to be notified via signal, | |
| 646 | * let them know the field is complete. | |
| 647 | */ | |
| 648 | if(mtr->proc && (mtr->signal & METEOR_SIG_MODE_MASK)) | |
| 84204577 | 649 | ksignal(mtr->proc, mtr->signal&(~METEOR_SIG_MODE_MASK)); |
| 984263bc MD |
650 | } |
| 651 | ||
| 652 | /* | |
| 653 | * If we have a complete frame. | |
| 654 | */ | |
| 655 | if(!(mtr->flags & METEOR_WANT_MASK)) { | |
| 656 | mtr->frames_captured++; | |
| 657 | /* | |
| 658 | * post the completion time. | |
| 659 | */ | |
| 660 | if(mtr->flags & METEOR_WANT_TS) { | |
| 661 | struct timeval *ts; | |
| 662 | ||
| 663 | if(mtr->alloc_pages * PAGE_SIZE <= (mtr->frame_size + | |
| 664 | sizeof(struct timeval))) { | |
| 665 | ts =(struct timeval *)mtr->bigbuf + | |
| 666 | mtr->frame_size; | |
| 667 | /* doesn't work in synch mode except for first frame */ | |
| 668 | /* XXX */ | |
| 669 | microtime(ts); | |
| 670 | } | |
| 671 | } | |
| 672 | /* | |
| 673 | * Wake up the user in single capture mode. | |
| 674 | */ | |
| 675 | if(mtr->flags & METEOR_SINGLE) | |
| 676 | wakeup((caddr_t)mtr); | |
| 677 | /* | |
| 678 | * If the user requested to be notified via signal, | |
| 679 | * let them know the frame is complete. | |
| 680 | */ | |
| 681 | if(mtr->proc && !(mtr->signal & METEOR_SIG_MODE_MASK)) | |
| 84204577 | 682 | ksignal(mtr->proc, mtr->signal&(~METEOR_SIG_MODE_MASK)); |
| 984263bc MD |
683 | /* |
| 684 | * Reset the want flags if in continuous or | |
| 685 | * synchronous capture mode. | |
| 686 | */ | |
| 687 | if(mtr->flags & (METEOR_CONTIN|METEOR_SYNCAP)) { | |
| 688 | switch(mtr->flags & METEOR_ONLY_FIELDS_MASK) { | |
| 689 | case METEOR_ONLY_ODD_FIELDS: | |
| 690 | mtr->flags |= METEOR_WANT_ODD; | |
| 691 | break; | |
| 692 | case METEOR_ONLY_EVEN_FIELDS: | |
| 693 | mtr->flags |= METEOR_WANT_EVEN; | |
| 694 | break; | |
| 695 | default: | |
| 696 | mtr->flags |= METEOR_WANT_MASK; | |
| 697 | break; | |
| 698 | } | |
| 699 | } | |
| 700 | /* | |
| 701 | * Special handling for synchronous capture mode. | |
| 702 | */ | |
| 703 | if(mtr->flags & METEOR_SYNCAP) { | |
| 704 | struct meteor_mem *mm = mtr->mem; | |
| 705 | /* | |
| 706 | * Mark the current frame as active. It is up to | |
| 707 | * the user to clear this, but we will clear it | |
| 708 | * for the user for the current frame being captured | |
| 709 | * if we are within the water marks (see below). | |
| 710 | */ | |
| 711 | mm->active |= 1 << (mtr->current - 1); | |
| 712 | ||
| 713 | /* | |
| 714 | * Since the user can muck with these values, we need | |
| 715 | * to check and see if they are sane. If they don't | |
| 716 | * pass the sanity check, disable the capture mode. | |
| 717 | * This is rather rude, but then so was the user. | |
| 718 | * | |
| 719 | * Do we really need all of this or should we just | |
| 720 | * eliminate the possiblity of allowing the | |
| 721 | * user to change hi and lo water marks while it | |
| 722 | * is running? XXX | |
| 723 | */ | |
| 724 | if(mm->num_active_bufs < 0 || | |
| 725 | mm->num_active_bufs > mtr->frames || | |
| 726 | mm->lowat < 1 || mm->lowat >= mtr->frames || | |
| 727 | mm->hiwat < 1 || mm->hiwat >= mtr->frames || | |
| 728 | mm->lowat > mm->hiwat ) { | |
| 729 | *cap &= 0x8ff0; | |
| 730 | mtr->flags &= ~(METEOR_SYNCAP|METEOR_WANT_MASK); | |
| 731 | } else { | |
| 732 | /* | |
| 733 | * Ok, they are sane, now we want to | |
| 734 | * check the water marks. | |
| 735 | */ | |
| 736 | if(mm->num_active_bufs <= mm->lowat) | |
| 737 | mtr->synch_wait = 0; | |
| 738 | if(mm->num_active_bufs >= mm->hiwat) | |
| 739 | mtr->synch_wait = 1; | |
| 740 | /* | |
| 741 | * Clear the active frame bit for this frame | |
| 742 | * and advance the counters if we are within | |
| 743 | * the banks of the water marks. | |
| 744 | */ | |
| 745 | if(!mtr->synch_wait) { | |
| 746 | mm->active &= ~(1 << mtr->current); | |
| 747 | mtr->current++; | |
| 748 | if(mtr->current > mtr->frames) | |
| 749 | mtr->current = 1; | |
| 750 | mm->num_active_bufs++; | |
| 751 | } | |
| 752 | } | |
| 753 | } | |
| 754 | } | |
| 755 | ||
| 756 | *stat |= 0x7; /* clear interrupt status */ | |
| 757 | return; | |
| 758 | } | |
| 759 | ||
| 760 | static void | |
| 761 | set_fps(meteor_reg_t *mtr, u_short fps) | |
| 762 | { | |
| 763 | struct saa7116_regs *s7116 = mtr->base; | |
| 764 | unsigned status; | |
| 765 | unsigned maxfps, mask = 0x1, length = 0; | |
| 766 | ||
| 767 | SAA7196_WRITE(mtr, SAA7196_STDC, SAA7196_REG(mtr, SAA7196_STDC) | 0x02); | |
| 768 | SAA7196_READ(mtr); | |
| 769 | status = (s7116->i2c_read & 0xff000000L) >> 24; | |
| 770 | ||
| 771 | /* | |
| 772 | * Determine if there is an input signal. Depending on the | |
| 773 | * frequency we either have a max of 25 fps (50 hz) or 30 fps (60 hz). | |
| 774 | * If there is no input signal, then we need some defaults. If the | |
| 775 | * user neglected to specify any defaults, just set to the fps to max. | |
| 776 | */ | |
| 777 | if((status & 0x40) == 0) { /* Is there a signal ? */ | |
| 778 | if(status & 0x20) { | |
| 779 | maxfps = 30; /* 60 hz system */ | |
| 780 | } else { | |
| 781 | maxfps = 25; /* 50 hz system */ | |
| 782 | } | |
| 783 | } else { /* We have no signal, check defaults */ | |
| 784 | #if METEOR_SYSTEM_DEFAULT == METEOR_PAL || METEOR_SYSTEM_DEFAULT == METEOR_SECAM | |
| 785 | maxfps = 25; | |
| 786 | #elif METEOR_SYSTEM_DEFAULT == METEOR_NTSC | |
| 787 | maxfps = 30; | |
| 788 | #else | |
| 789 | /* Don't really know what to do, just set max */ | |
| 790 | maxfps = 30; | |
| 791 | fps = 30; | |
| 792 | #endif | |
| 793 | } | |
| 794 | ||
| 795 | /* | |
| 796 | * A little sanity checking... | |
| 797 | */ | |
| 798 | if(fps < 1) fps = 1; | |
| 799 | if(fps > maxfps) fps = maxfps; | |
| 800 | ||
| 801 | /* | |
| 802 | * Compute the mask/length using the fps. | |
| 803 | */ | |
| 804 | if(fps == maxfps) { | |
| 805 | mask = 0x1; | |
| 806 | length = 0x0; | |
| 807 | } else if ((float)fps == maxfps/2.0) { | |
| 808 | mask = 0x1; | |
| 809 | length = 0x1; | |
| 810 | } else if (fps > maxfps/2) { | |
| 811 | float step, b; | |
| 812 | ||
| 813 | mask = (1<<maxfps) - 1; | |
| 814 | length = maxfps - 1; | |
| 815 | step = (float)(maxfps - 1)/(float)(maxfps - fps); | |
| 816 | for(b=step; b < maxfps; b += step) { | |
| 817 | mask &= ~(1<<((int)b)); /* mask out the bth frame */ | |
| 818 | } | |
| 819 | } else { /* fps < maxfps/2 */ | |
| 820 | float step, b; | |
| 821 | ||
| 822 | mask = 0x1; | |
| 823 | length = maxfps - 1; | |
| 824 | step = (float)(maxfps -1)/(float)(fps); | |
| 825 | for(b = step + 1; b < maxfps - 1; b += step) { | |
| 826 | mask |= (1<<((int)b)); /* mask in the bth frame */ | |
| 827 | } | |
| 828 | } | |
| 829 | ||
| 830 | /* | |
| 831 | * Set the fps. | |
| 832 | */ | |
| 833 | s7116->fme = s7116->fmo = mask; | |
| fc6d0222 | 834 | s7116->fml = (length << 16) | length; |
| 984263bc MD |
835 | |
| 836 | mtr->fps = fps; | |
| 837 | ||
| 838 | return; | |
| 839 | ||
| 840 | } | |
| 841 | ||
| 842 | /* | |
| 843 | * There is also a problem with range checking on the 7116. | |
| 844 | * It seems to only work for 22 bits, so the max size we can allocate | |
| 845 | * is 22 bits long or 4194304 bytes assuming that we put the beginning | |
| 846 | * of the buffer on a 2^24 bit boundary. The range registers will use | |
| 847 | * the top 8 bits of the dma start registers along with the bottom 22 | |
| 848 | * bits of the range register to determine if we go out of range. | |
| 849 | * This makes getting memory a real kludge. | |
| 850 | * | |
| 851 | */ | |
| 852 | #define RANGE_BOUNDARY (1<<22) | |
| 853 | static vm_offset_t | |
| 854 | get_meteor_mem(int unit, unsigned size) | |
| 855 | { | |
| 856 | vm_offset_t addr = 0; | |
| 857 | ||
| 858 | addr = vm_page_alloc_contig(size, 0, 0xffffffff, 1<<24); | |
| 859 | if(addr == 0) | |
| 860 | addr = vm_page_alloc_contig(size, 0, 0xffffffff, PAGE_SIZE); | |
| 861 | if(addr == 0) { | |
| e3869ec7 | 862 | kprintf("meteor%d: Unable to allocate %d bytes of memory.\n", |
| 984263bc MD |
863 | unit, size); |
| 864 | } | |
| 865 | ||
| 866 | return addr; | |
| 867 | } | |
| 868 | ||
| 869 | static void | |
| 870 | bt254_write(meteor_reg_t *mtr, u_char addr, u_char data) | |
| 871 | { | |
| 872 | addr &= 0x7; /* sanity? */ | |
| 873 | mtr->bt254_reg[addr] = data; | |
| 874 | PCF8574_DATA_WRITE(mtr, data); /* set data */ | |
| 875 | PCF8574_CTRL_WRITE(mtr, (PCF8574_CTRL_REG(mtr) & ~0x7) | addr); | |
| 876 | PCF8574_CTRL_WRITE(mtr, PCF8574_CTRL_REG(mtr) & ~0x10); /* WR/ to 0 */ | |
| 877 | PCF8574_CTRL_WRITE(mtr, PCF8574_CTRL_REG(mtr) | 0x10); /* WR to 1 */ | |
| 878 | PCF8574_DATA_WRITE(mtr, 0xff); /* clr data */ | |
| 879 | ||
| 880 | } | |
| 881 | ||
| 882 | static void | |
| 883 | bt254_init(meteor_reg_t *mtr) | |
| 884 | { | |
| 885 | int i; | |
| 886 | ||
| 887 | PCF8574_CTRL_WRITE(mtr, 0x7f); | |
| 888 | PCF8574_DATA_WRITE(mtr, 0xff); /* data port must be 0xff */ | |
| 889 | PCF8574_CTRL_WRITE(mtr, 0x7f); | |
| 890 | ||
| 891 | /* init RGB module for 24bpp, composite input */ | |
| 892 | for(i=0; i<NUM_BT254_REGS; i++) | |
| 893 | bt254_write(mtr, i, bt254_default[i]); | |
| 894 | ||
| 895 | bt254_write(mtr, BT254_COMMAND, 0x00); /* 24 bpp */ | |
| 896 | } | |
| 897 | ||
| 898 | static void | |
| 899 | bt254_ntsc(meteor_reg_t *mtr, int arg) | |
| 900 | { | |
| 901 | if (arg){ | |
| 902 | /* Set NTSC bit */ | |
| 903 | PCF8574_CTRL_WRITE(mtr, PCF8574_CTRL_REG(mtr) | 0x20); | |
| 904 | } | |
| 905 | else { | |
| 906 | /* reset NTSC bit */ | |
| 907 | PCF8574_CTRL_WRITE(mtr, PCF8574_CTRL_REG(mtr) &= ~0x20); | |
| 908 | } | |
| 909 | } | |
| 910 | ||
| 911 | static void | |
| 912 | select_bt254(meteor_reg_t *mtr) | |
| 913 | { | |
| 914 | /* disable saa7196, saaen = 1 */ | |
| 915 | PCF8574_CTRL_WRITE(mtr, PCF8574_CTRL_REG(mtr) | 0x80); | |
| 916 | /* enable Bt254, bten = 0 */ | |
| 917 | PCF8574_CTRL_WRITE(mtr, PCF8574_CTRL_REG(mtr) & ~0x40); | |
| 918 | } | |
| 919 | ||
| 920 | static void | |
| 921 | select_saa7196(meteor_reg_t *mtr) | |
| 922 | { | |
| 923 | /* disable Bt254, bten = 1 */ | |
| 924 | PCF8574_CTRL_WRITE(mtr, PCF8574_CTRL_REG(mtr) | 0x40); | |
| 925 | /* enable saa7196, saaen = 0 */ | |
| 926 | PCF8574_CTRL_WRITE(mtr, PCF8574_CTRL_REG(mtr) & ~0x80); | |
| 927 | } | |
| 928 | ||
| 929 | /* | |
| 930 | * Initialize the 7116, 7196 and the RGB module. | |
| 931 | */ | |
| 932 | static void | |
| 933 | meteor_init ( meteor_reg_t *mtr ) | |
| 934 | { | |
| 935 | mreg_t *vbase_addr; | |
| 936 | int i; | |
| 937 | ||
| 938 | /* | |
| 939 | * Initialize the Philips SAA7116 | |
| 940 | */ | |
| 941 | mtr->base->cap_cntl = 0x00000040L; | |
| 942 | vbase_addr = &mtr->base->dma1e; | |
| 943 | for (i = 0 ; i < (sizeof(struct saa7116_regs)/sizeof(mreg_t)); i++) | |
| 944 | *vbase_addr++ = saa7116_pci_default[i]; | |
| 945 | ||
| 946 | /* | |
| 947 | * Check for the Philips SAA7196 | |
| 948 | */ | |
| 949 | i2c_print_err = 0; | |
| 950 | if(i2c_write(mtr, SAA7196_I2C_ADDR, SAA7116_I2C_WRITE, 0, 0xff) == 0) { | |
| 951 | i2c_print_err = 1; | |
| 952 | /* | |
| 953 | * Initialize 7196 | |
| 954 | */ | |
| 955 | for (i = 0; i < NUM_SAA7196_I2C_REGS; i++) | |
| 956 | SAA7196_WRITE(mtr, i, saa7196_i2c_default[i]); | |
| 957 | /* | |
| 958 | * Get version number. | |
| 959 | */ | |
| 960 | SAA7196_WRITE(mtr, SAA7196_STDC, | |
| 961 | SAA7196_REG(mtr, SAA7196_STDC) & ~0x02); | |
| 962 | SAA7196_READ(mtr); | |
| e3869ec7 | 963 | kprintf("meteor%d: <Philips SAA 7196> rev 0x%x\n", |
| 984263bc MD |
964 | METEOR_NUM(mtr), |
| 965 | (unsigned)((mtr->base->i2c_read & 0xff000000L) >> 28)); | |
| 966 | } else { | |
| 967 | i2c_print_err = 1; | |
| e3869ec7 | 968 | kprintf("meteor%d: <Philips SAA 7196 NOT FOUND>\n", |
| 984263bc MD |
969 | METEOR_NUM(mtr)); |
| 970 | } | |
| 971 | /* | |
| 972 | * Check for RGB module, initialized if found. | |
| 973 | */ | |
| 974 | i2c_print_err = 0; | |
| 975 | if(i2c_write(mtr,PCF8574_DATA_I2C_ADDR,SAA7116_I2C_WRITE,0,0xff) == 0) { | |
| 976 | i2c_print_err = 1; | |
| e3869ec7 | 977 | kprintf("meteor%d: <Booktree 254 (RGB module)>\n", |
| 984263bc MD |
978 | METEOR_NUM(mtr)); /* does this have a rev #? */ |
| 979 | bt254_init(mtr); /* Set up RGB module */ | |
| 980 | mtr->flags = METEOR_RGB; | |
| 981 | } else { | |
| 982 | i2c_print_err = 1; | |
| 983 | mtr->flags = 0; | |
| 984 | } | |
| 985 | ||
| 986 | set_fps(mtr, 30); | |
| 987 | ||
| 988 | } | |
| 989 | ||
| 990 | static void | |
| 991 | met_attach(pcici_t tag, int unit) | |
| 992 | { | |
| 993 | #ifdef METEOR_IRQ | |
| 994 | u_long old_irq, new_irq; | |
| 06dca418 | 995 | #endif /* METEOR_IRQ */ |
| 984263bc MD |
996 | meteor_reg_t *mtr; |
| 997 | vm_offset_t buf; | |
| 998 | u_long latency; | |
| 999 | ||
| 1000 | if (unit >= NMETEOR) { | |
| e3869ec7 | 1001 | kprintf("meteor%d: attach: only %d units configured.\n", |
| 984263bc | 1002 | unit, NMETEOR); |
| e3869ec7 | 1003 | kprintf("meteor%d: attach: invalid unit number.\n", unit); |
| 984263bc MD |
1004 | return ; |
| 1005 | } | |
| 1006 | ||
| 1007 | /* | |
| 1008 | * Check for Meteor/PPB (PCI-PCI Bridge) | |
| 1009 | * Reprogram IBM Bridge if detected. | |
| 1010 | * New Meteor cards have an IBM PCI-PCI bridge, creating a secondary | |
| 1011 | * PCI bus. The SAA chip is connected to this secondary bus. | |
| 1012 | */ | |
| 1013 | ||
| 1014 | /* If we are not on PCI Bus 0, check for the Bridge */ | |
| 1015 | if ( pci_get_bus_from_tag( tag ) != 0) { | |
| 1016 | pcici_t bridge_tag; | |
| 1017 | ||
| 1018 | /* get tag of parent bridge */ | |
| 1019 | bridge_tag = pci_get_parent_from_tag( tag ); | |
| 1020 | ||
| 1021 | /* Look for IBM 82351, 82352 or 82353 */ | |
| 1022 | if (pci_conf_read(bridge_tag, PCI_ID_REG) == 0x00221014) { | |
| 1023 | ||
| 1024 | if ( bootverbose) | |
| e3869ec7 | 1025 | kprintf("meteor%d: PPB device detected, reprogramming IBM bridge.\n", unit); |
| 984263bc MD |
1026 | |
| 1027 | /* disable SERR */ | |
| 1028 | pci_cfgwrite(bridge_tag, 0x05, 0x00, 1); | |
| 1029 | /* set LATENCY */ | |
| 1030 | pci_cfgwrite(bridge_tag, 0x0d, 0x20, 1); | |
| 1031 | /* write posting enable, prefetch enabled --> GRAB direction */ | |
| 1032 | pci_cfgwrite(bridge_tag, 0x42, 0x14, 1); | |
| 1033 | /* set PRTR Primary retry timer register */ | |
| 1034 | pci_cfgwrite(bridge_tag, 0x4c, 0x10, 1); | |
| 1035 | } | |
| 1036 | } | |
| 1037 | ||
| 1038 | mtr = &meteor[unit]; | |
| 1039 | mtr->tag = tag; | |
| 1040 | pci_map_mem(tag, PCI_MAP_REG_START, (vm_offset_t *)&mtr->base, | |
| 1041 | &mtr->phys_base); | |
| 1042 | ||
| 1043 | #ifdef METEOR_IRQ /* from the configuration file */ | |
| 1044 | old_irq = pci_conf_read(tag, PCI_INTERRUPT_REG); | |
| 1045 | pci_conf_write(tag, PCI_INTERRUPT_REG, METEOR_IRQ); | |
| 1046 | new_irq = pci_conf_read(tag, PCI_INTERRUPT_REG); | |
| e3869ec7 | 1047 | kprintf("meteor%d: attach: irq changed from %d to %d\n", |
| 984263bc | 1048 | unit, (old_irq & 0xff), (new_irq & 0xff)); |
| 06dca418 | 1049 | #endif /* METEOR_IRQ */ |
| 984263bc | 1050 | /* setup the interrupt handling routine */ |
| 38787eef | 1051 | pci_map_int(tag, meteor_intr, (void*) mtr); |
| 984263bc MD |
1052 | |
| 1053 | /* | |
| 1054 | * PCI latency timer. 32 is a good value for 4 bus mastering slots, if | |
| 1055 | * you have more than for, then 16 would probably be a better value. | |
| 1056 | * | |
| 1057 | */ | |
| 1058 | #ifndef METEOR_DEF_LATENCY_VALUE | |
| 1059 | #define METEOR_DEF_LATENCY_VALUE 32 | |
| 1060 | #endif | |
| 1061 | latency = pci_conf_read(tag, PCI_LATENCY_TIMER); | |
| 1062 | latency = (latency >> 8) & 0xff; | |
| 1063 | if(bootverbose) { | |
| 1064 | if(latency) | |
| e3869ec7 | 1065 | kprintf("meteor%d: PCI bus latency is", unit); |
| 984263bc | 1066 | else |
| e3869ec7 | 1067 | kprintf("meteor%d: PCI bus latency was 0 changing to", |
| 984263bc MD |
1068 | unit); |
| 1069 | } | |
| 1070 | if(!latency) { | |
| 1071 | latency = METEOR_DEF_LATENCY_VALUE; | |
| 1072 | pci_conf_write(tag, PCI_LATENCY_TIMER, latency<<8); | |
| 1073 | } | |
| 1074 | if(bootverbose) { | |
| e3869ec7 | 1075 | kprintf(" %lu.\n", latency); |
| 984263bc MD |
1076 | } |
| 1077 | ||
| 1078 | meteor_init(mtr); /* set up saa7116, saa7196, and rgb module */ | |
| 1079 | ||
| 1080 | if(METEOR_ALLOC) | |
| 1081 | buf = get_meteor_mem(unit, METEOR_ALLOC); | |
| 1082 | else | |
| 1083 | buf = 0; | |
| 1084 | if(bootverbose) { | |
| e3869ec7 | 1085 | kprintf("meteor%d: buffer size %d, addr 0x%llx\n", |
| 984263bc MD |
1086 | unit, METEOR_ALLOC, vtophys(buf)); |
| 1087 | } | |
| 1088 | ||
| 1089 | mtr->bigbuf = buf; | |
| 1090 | mtr->alloc_pages = METEOR_ALLOC_PAGES; | |
| 1091 | if(buf != 0) { | |
| 1092 | bzero((caddr_t) buf, METEOR_ALLOC); | |
| 1093 | buf = vtophys(buf); | |
| 1094 | /* 640x480 RGB 16 */ | |
| 1095 | mtr->base->dma1e = buf; | |
| 1096 | mtr->base->dma1o = buf + 0x500; | |
| 1097 | mtr->base->dma_end_e = | |
| 1098 | mtr->base->dma_end_o = buf + METEOR_ALLOC; | |
| 1099 | } | |
| 1100 | /* 1 frame of 640x480 RGB 16 */ | |
| 1101 | mtr->cols = 640; | |
| 1102 | mtr->rows = 480; | |
| 1103 | mtr->depth = 2; /* two bytes per pixel */ | |
| 1104 | mtr->frames = 1; /* one frame */ | |
| 1105 | ||
| 1106 | mtr->flags |= METEOR_INITALIZED | METEOR_AUTOMODE | METEOR_DEV0 | | |
| 3e82b46c | 1107 | METEOR_RGB16; |
| fef8985e | 1108 | make_dev(&meteor_ops, unit, 0, 0, 0644, "meteor"); |
| 984263bc MD |
1109 | } |
| 1110 | ||
| 1111 | #define UNIT(x) ((x) & 0x07) | |
| 1112 | ||
| 1113 | #ifdef unused | |
| 1114 | static int | |
| b13267a5 | 1115 | meteor_reset(cdev_t dev) |
| 984263bc MD |
1116 | { |
| 1117 | int unit = UNIT(minor(dev)); | |
| 1118 | struct saa7116_regs *m; | |
| 1119 | ||
| 1120 | if(unit >= NMETEOR) | |
| 1121 | return ENXIO; | |
| 1122 | ||
| 1123 | m = meteor[unit].base; | |
| 1124 | ||
| 1125 | m->cap_cntl = 0x0; | |
| 1126 | tsleep((caddr_t)m, METPRI, "Mreset", hz/50); | |
| 1127 | ||
| 1128 | m->cap_cntl = 0x8ff0; | |
| 1129 | m->cap_cntl = 0x80c0; | |
| 1130 | m->cap_cntl = 0x8040; | |
| 1131 | tsleep((caddr_t)m, METPRI, "Mreset", hz/10); | |
| 1132 | m->cap_cntl = 0x80c0; | |
| 1133 | ||
| 1134 | return 0; | |
| 1135 | ||
| 1136 | } | |
| 1137 | #endif | |
| 1138 | ||
| 1139 | /*--------------------------------------------------------- | |
| 1140 | ** | |
| 1141 | ** Meteor character device driver routines | |
| 1142 | ** | |
| 1143 | **--------------------------------------------------------- | |
| 1144 | */ | |
| 1145 | ||
| 984263bc | 1146 | int |
| fef8985e | 1147 | meteor_open(struct dev_open_args *ap) |
| 984263bc | 1148 | { |
| b13267a5 | 1149 | cdev_t dev = ap->a_head.a_dev; |
| 984263bc MD |
1150 | meteor_reg_t *mtr; |
| 1151 | int unit; | |
| 1152 | int i; | |
| 1153 | ||
| 1154 | unit = UNIT(minor(dev)); | |
| 1155 | if (unit >= NMETEOR) /* unit out of range */ | |
| 1156 | return(ENXIO); | |
| 1157 | ||
| 1158 | mtr = &(meteor[unit]); | |
| 1159 | ||
| 1160 | if (!(mtr->flags & METEOR_INITALIZED)) /* device not found */ | |
| 1161 | return(ENXIO); | |
| 1162 | ||
| 1163 | if (mtr->flags & METEOR_OPEN) /* device is busy */ | |
| 1164 | return(EBUSY); | |
| 1165 | ||
| 1166 | mtr->flags |= METEOR_OPEN; | |
| 1167 | /* | |
| 1168 | * Make sure that the i2c regs are set the same for each open. | |
| 1169 | */ | |
| 1170 | for(i=0; i< NUM_SAA7196_I2C_REGS; i++) { | |
| 1171 | SAA7196_WRITE(mtr, i, saa7196_i2c_default[i]); | |
| 1172 | } | |
| 1173 | ||
| 1174 | mtr->fifo_errors = 0; | |
| 1175 | mtr->dma_errors = 0; | |
| 1176 | mtr->frames_captured = 0; | |
| 1177 | mtr->even_fields_captured = 0; | |
| 1178 | mtr->odd_fields_captured = 0; | |
| 60233e58 | 1179 | mtr->proc = NULL; |
| 984263bc MD |
1180 | set_fps(mtr, 30); |
| 1181 | #ifdef METEOR_TEST_VIDEO | |
| 1182 | mtr->video.addr = 0; | |
| 1183 | mtr->video.width = 0; | |
| 1184 | mtr->video.banksize = 0; | |
| 1185 | mtr->video.ramsize = 0; | |
| 1186 | #endif | |
| 1187 | ||
| 1188 | return(0); | |
| 1189 | } | |
| 1190 | ||
| 1191 | int | |
| fef8985e | 1192 | meteor_close(struct dev_close_args *ap) |
| 984263bc | 1193 | { |
| b13267a5 | 1194 | cdev_t dev = ap->a_head.a_dev; |
| 984263bc MD |
1195 | meteor_reg_t *mtr; |
| 1196 | int unit; | |
| 1197 | #ifdef METEOR_DEALLOC_ABOVE | |
| 1198 | int temp; | |
| 1199 | #endif | |
| 1200 | ||
| 1201 | unit = UNIT(minor(dev)); | |
| 1202 | if (unit >= NMETEOR) /* unit out of range */ | |
| 1203 | return(ENXIO); | |
| 1204 | ||
| 1205 | mtr = &(meteor[unit]); | |
| 1206 | mtr->flags &= ~METEOR_OPEN; | |
| 1207 | ||
| 1208 | if(mtr->flags & METEOR_SINGLE) | |
| 1209 | /* this should not happen, the read capture | |
| 1210 | should have completed or in the very least | |
| 1211 | recieved a signal before close is called. */ | |
| 1212 | wakeup((caddr_t)mtr); /* continue read */ | |
| 1213 | /* | |
| 1214 | * Turn off capture mode. | |
| 1215 | */ | |
| 1216 | mtr->base->cap_cntl = 0x8ff0; | |
| 1217 | mtr->flags &= ~(METEOR_CAP_MASK|METEOR_WANT_MASK); | |
| 60233e58 | 1218 | mtr->proc = NULL; |
| 984263bc MD |
1219 | |
| 1220 | #ifdef METEOR_DEALLOC_PAGES | |
| 1221 | if (mtr->bigbuf != NULL) { | |
| e4846942 MD |
1222 | kmem_free(&kernel_map, mtr->bigbuf, |
| 1223 | (mtr->alloc_pages * PAGE_SIZE)); | |
| 984263bc MD |
1224 | mtr->bigbuf = NULL; |
| 1225 | mtr->alloc_pages = 0; | |
| 1226 | } | |
| 1227 | #else | |
| 1228 | #ifdef METEOR_DEALLOC_ABOVE | |
| 1229 | if (mtr->bigbuf != NULL && mtr->alloc_pages > METEOR_DEALLOC_ABOVE) { | |
| 1230 | temp = METEOR_DEALLOC_ABOVE - mtr->alloc_pages; | |
| e4846942 | 1231 | kmem_free(&kernel_map, |
| 984263bc MD |
1232 | mtr->bigbuf+((mtr->alloc_pages - temp) * PAGE_SIZE), |
| 1233 | (temp * PAGE_SIZE)); | |
| 1234 | mtr->alloc_pages = METEOR_DEALLOC_ABOVE; | |
| 1235 | } | |
| 1236 | #endif | |
| 1237 | #endif | |
| 1238 | ||
| 1239 | return(0); | |
| 1240 | } | |
| 1241 | ||
| 1242 | static void | |
| 1243 | start_capture(meteor_reg_t *mtr, unsigned type) | |
| 1244 | { | |
| 1245 | mreg_t *cap = &mtr->base->cap_cntl; | |
| 1246 | ||
| 1247 | mtr->flags |= type; | |
| 1248 | switch(mtr->flags & METEOR_ONLY_FIELDS_MASK) { | |
| 1249 | case METEOR_ONLY_EVEN_FIELDS: | |
| 1250 | mtr->flags |= METEOR_WANT_EVEN; | |
| 1251 | if(type == METEOR_SINGLE) | |
| 1252 | *cap = 0x0ff4 | mtr->range_enable; | |
| 1253 | else | |
| 1254 | *cap = 0x0ff1 | mtr->range_enable; | |
| 1255 | break; | |
| 1256 | case METEOR_ONLY_ODD_FIELDS: | |
| 1257 | mtr->flags |= METEOR_WANT_ODD; | |
| 1258 | if(type == METEOR_SINGLE) | |
| 1259 | *cap = 0x0ff8 | mtr->range_enable; | |
| 1260 | else | |
| 1261 | *cap = 0x0ff2 | mtr->range_enable; | |
| 1262 | break; | |
| 1263 | default: | |
| 1264 | mtr->flags |= METEOR_WANT_MASK; | |
| 1265 | if(type == METEOR_SINGLE) | |
| 1266 | *cap = 0x0ffc | mtr->range_enable; | |
| 1267 | else | |
| 1268 | *cap = 0x0ff3 | mtr->range_enable; | |
| 1269 | break; | |
| 1270 | } | |
| 1271 | } | |
| 1272 | ||
| 1273 | int | |
| fef8985e | 1274 | meteor_read(struct dev_read_args *ap) |
| 984263bc | 1275 | { |
| b13267a5 | 1276 | cdev_t dev = ap->a_head.a_dev; |
| fef8985e | 1277 | struct uio *uio = ap->a_uio; |
| 984263bc MD |
1278 | meteor_reg_t *mtr; |
| 1279 | int unit; | |
| 1280 | int status; | |
| 1281 | int count; | |
| 1282 | ||
| 1283 | unit = UNIT(minor(dev)); | |
| 1284 | if (unit >= NMETEOR) /* unit out of range */ | |
| 1285 | return(ENXIO); | |
| 1286 | ||
| 1287 | mtr = &(meteor[unit]); | |
| 1288 | if (mtr->bigbuf == 0)/* no frame buffer allocated (ioctl failed) */ | |
| 1289 | return(ENOMEM); | |
| 1290 | ||
| 1291 | if (mtr->flags & METEOR_CAP_MASK) | |
| 1292 | return(EIO); /* already capturing */ | |
| 1293 | ||
| 1294 | count = mtr->rows * mtr->cols * mtr->depth; | |
| 1295 | if (uio->uio_iov->iov_len < count) | |
| 1296 | return(EINVAL); | |
| 1297 | ||
| 1298 | /* Start capture */ | |
| 1299 | start_capture(mtr, METEOR_SINGLE); | |
| 1300 | ||
| 1301 | status=tsleep((caddr_t)mtr, METPRI, "capturing", 0); | |
| 1302 | if (!status) /* successful capture */ | |
| 1303 | status = uiomove((caddr_t)mtr->bigbuf, count, uio); | |
| 1304 | else | |
| e3869ec7 | 1305 | kprintf ("meteor%d: read: tsleep error %d\n", unit, status); |
| 984263bc MD |
1306 | |
| 1307 | mtr->flags &= ~(METEOR_SINGLE | METEOR_WANT_MASK); | |
| 1308 | ||
| 1309 | return(status); | |
| 1310 | } | |
| 1311 | ||
| 1312 | int | |
| fef8985e | 1313 | meteor_write(struct dev_write_args *ap) |
| 984263bc MD |
1314 | { |
| 1315 | return(0); | |
| 1316 | } | |
| 1317 | ||
| 1318 | int | |
| fef8985e | 1319 | meteor_ioctl(struct dev_ioctl_args *ap) |
| 984263bc | 1320 | { |
| b13267a5 | 1321 | cdev_t dev = ap->a_head.a_dev; |
| fef8985e | 1322 | caddr_t data = ap->a_data; |
| 984263bc MD |
1323 | int error; |
| 1324 | int unit; | |
| 1325 | unsigned int temp; | |
| 1326 | meteor_reg_t *mtr; | |
| 1327 | struct meteor_counts *cnt; | |
| 1328 | struct meteor_geomet *geo; | |
| 1329 | struct meteor_mem *mem; | |
| 1330 | struct meteor_capframe *frame; | |
| 1331 | #ifdef METEOR_TEST_VIDEO | |
| 1332 | struct meteor_video *video; | |
| 1333 | #endif | |
| 1334 | vm_offset_t buf; | |
| 1335 | struct saa7116_regs *base; | |
| 1336 | ||
| 1337 | error = 0; | |
| 1338 | ||
| fef8985e MD |
1339 | if (data == NULL) |
| 1340 | return(EINVAL); | |
| 984263bc MD |
1341 | unit = UNIT(minor(dev)); |
| 1342 | if (unit >= NMETEOR) /* unit out of range */ | |
| 1343 | return(ENXIO); | |
| 1344 | ||
| 1345 | mtr = &(meteor[unit]); | |
| 1346 | base = mtr->base; | |
| 1347 | ||
| fef8985e | 1348 | switch (ap->a_cmd) { |
| 984263bc | 1349 | case METEORSTS: |
| fef8985e | 1350 | if(*data) |
| 984263bc MD |
1351 | mtr->flags |= METEOR_WANT_TS; |
| 1352 | else | |
| 1353 | mtr->flags &= ~METEOR_WANT_TS; | |
| 1354 | break; | |
| 1355 | case METEORGTS: | |
| 1356 | if(mtr->flags & METEOR_WANT_TS) | |
| fef8985e | 1357 | *data = 1; |
| 984263bc | 1358 | else |
| fef8985e | 1359 | *data = 0; |
| 984263bc MD |
1360 | break; |
| 1361 | #ifdef METEOR_TEST_VIDEO | |
| 1362 | case METEORGVIDEO: | |
| fef8985e | 1363 | video = (struct meteor_video *)data; |
| 984263bc MD |
1364 | video->addr = mtr->video.addr; |
| 1365 | video->width = mtr->video.width; | |
| 1366 | video->banksize = mtr->video.banksize; | |
| 1367 | video->ramsize = mtr->video.ramsize; | |
| 1368 | break; | |
| 1369 | case METEORSVIDEO: | |
| fef8985e | 1370 | video = (struct meteor_video *)data; |
| 984263bc MD |
1371 | mtr->video.addr = video->addr; |
| 1372 | mtr->video.width = video->width; | |
| 1373 | mtr->video.banksize = video->banksize; | |
| 1374 | mtr->video.ramsize = video->ramsize; | |
| 1375 | break; | |
| 1376 | #endif | |
| 1377 | case METEORSFPS: | |
| fef8985e | 1378 | set_fps(mtr, *(u_short *)data); |
| 984263bc MD |
1379 | break; |
| 1380 | case METEORGFPS: | |
| fef8985e | 1381 | *(u_short *)data = mtr->fps; |
| 984263bc MD |
1382 | break; |
| 1383 | case METEORSSIGNAL: | |
| fef8985e | 1384 | if (*(int *)data < 0 || *(int *)data > _SIG_MAXSIG) |
| d82eda3e | 1385 | return EINVAL; |
| fef8985e | 1386 | mtr->signal = *(int *) data; |
| 984263bc | 1387 | if (mtr->signal) { |
| fef8985e | 1388 | mtr->proc = curproc; /* might be NULL */ |
| 984263bc | 1389 | } else { |
| 60233e58 | 1390 | mtr->proc = NULL; |
| 984263bc MD |
1391 | } |
| 1392 | break; | |
| 1393 | case METEORGSIGNAL: | |
| fef8985e | 1394 | *(int *)data = mtr->signal; |
| 984263bc MD |
1395 | break; |
| 1396 | case METEORSTATUS: /* get 7196 status */ | |
| 1397 | temp = 0; | |
| 1398 | SAA7196_WRITE(mtr, SAA7196_STDC, | |
| 1399 | SAA7196_REG(mtr, SAA7196_STDC) | 0x02); | |
| 1400 | SAA7196_READ(mtr); | |
| 1401 | temp |= (base->i2c_read & 0xff000000L) >> 24; | |
| 1402 | SAA7196_WRITE(mtr, SAA7196_STDC, | |
| 1403 | SAA7196_REG(mtr, SAA7196_STDC) & ~0x02); | |
| 1404 | SAA7196_READ(mtr); | |
| 1405 | temp |= (base->i2c_read & 0xff000000L) >> 16; | |
| fef8985e | 1406 | *(u_short *)data = temp; |
| 984263bc MD |
1407 | break; |
| 1408 | case METEORSHUE: /* set hue */ | |
| fef8985e | 1409 | SAA7196_WRITE(mtr, SAA7196_HUEC, *(char *)data); |
| 984263bc MD |
1410 | break; |
| 1411 | case METEORGHUE: /* get hue */ | |
| fef8985e | 1412 | *(char *)data = SAA7196_REG(mtr, SAA7196_HUEC); |
| 984263bc MD |
1413 | break; |
| 1414 | case METEORSCHCV: /* set chrominance gain */ | |
| fef8985e | 1415 | SAA7196_WRITE(mtr, SAA7196_CGAINR, *(char *)data); |
| 984263bc MD |
1416 | break; |
| 1417 | case METEORGCHCV: /* get chrominance gain */ | |
| fef8985e | 1418 | *(char *)data = SAA7196_REG(mtr, SAA7196_CGAINR); |
| 984263bc MD |
1419 | break; |
| 1420 | case METEORSBRIG: /* set brightness */ | |
| fef8985e | 1421 | SAA7196_WRITE(mtr, SAA7196_BRIG, *(char *)data); |
| 984263bc MD |
1422 | break; |
| 1423 | case METEORGBRIG: /* get brightness */ | |
| fef8985e | 1424 | *(char *)data = SAA7196_REG(mtr, SAA7196_BRIG); |
| 984263bc MD |
1425 | break; |
| 1426 | case METEORSCSAT: /* set chroma saturation */ | |
| fef8985e | 1427 | SAA7196_WRITE(mtr, SAA7196_CSAT, *(char *)data); |
| 984263bc MD |
1428 | break; |
| 1429 | case METEORGCSAT: /* get chroma saturation */ | |
| fef8985e | 1430 | *(char *)data = SAA7196_REG(mtr, SAA7196_CSAT); |
| 984263bc MD |
1431 | break; |
| 1432 | case METEORSCONT: /* set contrast */ | |
| fef8985e | 1433 | SAA7196_WRITE(mtr, SAA7196_CONT, *(char *)data); |
| 984263bc MD |
1434 | break; |
| 1435 | case METEORGCONT: /* get contrast */ | |
| fef8985e | 1436 | *(char *)data = SAA7196_REG(mtr, SAA7196_CONT); |
| 984263bc MD |
1437 | break; |
| 1438 | case METEORSBT254: | |
| 1439 | if((mtr->flags & METEOR_RGB) == 0) | |
| 1440 | return EINVAL; | |
| fef8985e | 1441 | temp = *(unsigned short *)data; |
| 984263bc MD |
1442 | bt254_write(mtr, temp & 0xf, (temp & 0x0ff0) >> 4); |
| 1443 | break; | |
| 1444 | case METEORGBT254: | |
| 1445 | if((mtr->flags & METEOR_RGB) == 0) | |
| 1446 | return EINVAL; | |
| fef8985e MD |
1447 | temp = *(unsigned short *)data & 0x7; |
| 1448 | *(unsigned short *)data = mtr->bt254_reg[temp] << 4 | temp; | |
| 984263bc MD |
1449 | break; |
| 1450 | case METEORSHWS: /* set horizontal window start */ | |
| fef8985e | 1451 | SAA7196_WRITE(mtr, SAA7196_HWS, *(char *)data); |
| 984263bc MD |
1452 | break; |
| 1453 | case METEORGHWS: /* get horizontal window start */ | |
| fef8985e | 1454 | *(char *)data = SAA7196_REG(mtr, SAA7196_HWS); |
| 984263bc MD |
1455 | break; |
| 1456 | case METEORSVWS: /* set vertical window start */ | |
| fef8985e | 1457 | SAA7196_WRITE(mtr, SAA7196_VWS, *(char *)data); |
| 984263bc MD |
1458 | break; |
| 1459 | case METEORGVWS: /* get vertical window start */ | |
| fef8985e | 1460 | *(char *)data = SAA7196_REG(mtr, SAA7196_VWS); |
| 984263bc MD |
1461 | break; |
| 1462 | case METEORSINPUT: /* set input device */ | |
| fef8985e | 1463 | switch(*(unsigned long *)data & METEOR_DEV_MASK) { |
| 984263bc MD |
1464 | case 0: /* default */ |
| 1465 | case METEOR_INPUT_DEV0: | |
| 1466 | if(mtr->flags & METEOR_RGB) | |
| 1467 | select_saa7196(mtr); | |
| 1468 | mtr->flags = (mtr->flags & ~METEOR_DEV_MASK) | |
| 1469 | | METEOR_DEV0; | |
| 1470 | SAA7196_WRITE(mtr, 0x0e, | |
| 1471 | (SAA7196_REG(mtr, 0x0e) & ~0x3) | 0x0); | |
| 1472 | SAA7196_WRITE(mtr, 0x06, | |
| 1473 | (SAA7196_REG(mtr, 0x06) & ~0x80)); | |
| 1474 | break; | |
| 1475 | case METEOR_INPUT_DEV1: | |
| 1476 | if(mtr->flags & METEOR_RGB) | |
| 1477 | select_saa7196(mtr); | |
| 1478 | mtr->flags = (mtr->flags & ~METEOR_DEV_MASK) | |
| 1479 | | METEOR_DEV1; | |
| 1480 | SAA7196_WRITE(mtr, 0x0e, | |
| 1481 | (SAA7196_REG(mtr, 0x0e) & ~0x3) | 0x1); | |
| 1482 | SAA7196_WRITE(mtr, 0x06, | |
| 1483 | (SAA7196_REG(mtr, 0x06) & ~0x80)); | |
| 1484 | break; | |
| 1485 | case METEOR_INPUT_DEV2: | |
| 1486 | if(mtr->flags & METEOR_RGB) | |
| 1487 | select_saa7196(mtr); | |
| 1488 | mtr->flags = (mtr->flags & ~METEOR_DEV_MASK) | |
| 1489 | | METEOR_DEV2; | |
| 1490 | SAA7196_WRITE(mtr, 0x0e, | |
| 1491 | (SAA7196_REG(mtr, 0x0e) & ~0x3) | 0x2); | |
| 1492 | SAA7196_WRITE(mtr, 0x06, | |
| 1493 | (SAA7196_REG(mtr, 0x06) & ~0x80)); | |
| 1494 | break; | |
| 1495 | case METEOR_INPUT_DEV3: | |
| 1496 | if(mtr->flags & METEOR_RGB) | |
| 1497 | select_saa7196(mtr); | |
| 1498 | mtr->flags = (mtr->flags & ~METEOR_DEV_MASK) | |
| 1499 | | METEOR_DEV3; | |
| 1500 | SAA7196_WRITE(mtr, 0x0e, | |
| 1501 | (SAA7196_REG(mtr, 0x0e) | 0x3)); | |
| 1502 | SAA7196_WRITE(mtr, 0x06, | |
| 1503 | (SAA7196_REG(mtr, 0x06) & ~0x80) ); | |
| 1504 | break; | |
| 1505 | case METEOR_INPUT_DEV_SVIDEO: | |
| 1506 | if(mtr->flags & METEOR_RGB) | |
| 1507 | select_saa7196(mtr); | |
| 1508 | mtr->flags = (mtr->flags & ~METEOR_DEV_MASK) | |
| 1509 | | METEOR_DEV_SVIDEO; | |
| 1510 | SAA7196_WRITE(mtr, 0x0e, | |
| 1511 | (SAA7196_REG(mtr, 0x0e) & ~0x3) | 0x2); | |
| 1512 | SAA7196_WRITE(mtr, 0x06, | |
| 1513 | (SAA7196_REG(mtr, 0x06) & ~0x80) | 0x80); | |
| 1514 | break; | |
| 1515 | case METEOR_INPUT_DEV_RGB: | |
| 1516 | if((mtr->flags & METEOR_RGB) == 0) | |
| 1517 | return EINVAL; | |
| 1518 | mtr->flags = (mtr->flags & ~METEOR_DEV_MASK) | |
| 1519 | | METEOR_DEV_RGB; | |
| 1520 | SAA7196_WRITE(mtr, 0x0e, | |
| 1521 | (SAA7196_REG(mtr, 0x0e) & ~0x3) | 0x3); | |
| 1522 | SAA7196_WRITE(mtr, 0x06, | |
| 1523 | (SAA7196_REG(mtr, 0x06) & ~0x80)); | |
| 1524 | select_bt254(mtr); | |
| 1525 | SAA7196_WRITE(mtr, 0x0e, /* chn 3 for synch */ | |
| 1526 | (SAA7196_REG(mtr, 0x0e) & ~0x3) | 0x3); | |
| 1527 | break; | |
| 1528 | default: | |
| 1529 | return EINVAL; | |
| 1530 | } | |
| 1531 | break; | |
| 1532 | case METEORGINPUT: /* get input device */ | |
| fef8985e | 1533 | *(u_long *)data = mtr->flags & METEOR_DEV_MASK; |
| 984263bc MD |
1534 | break; |
| 1535 | case METEORSFMT: /* set input format */ | |
| fef8985e | 1536 | switch(*(unsigned long *)data & METEOR_FORM_MASK ) { |
| 984263bc MD |
1537 | case 0: /* default */ |
| 1538 | case METEOR_FMT_NTSC: | |
| 1539 | mtr->flags = (mtr->flags & ~METEOR_FORM_MASK) | | |
| 1540 | METEOR_NTSC; | |
| 1541 | SAA7196_WRITE(mtr, SAA7196_STDC, | |
| 1542 | (SAA7196_REG(mtr, SAA7196_STDC) & ~0x01)); | |
| 1543 | SAA7196_WRITE(mtr, 0x0f, | |
| 1544 | (SAA7196_REG(mtr, 0x0f) & ~0xe0) | 0x40); | |
| 1545 | SAA7196_WRITE(mtr, 0x22, 0x80); | |
| 1546 | SAA7196_WRITE(mtr, 0x24, | |
| 1547 | (SAA7196_REG(mtr, 0x24) & ~0x0c) | 0x08); | |
| 1548 | SAA7196_WRITE(mtr, 0x26, 0xf0); | |
| 1549 | SAA7196_WRITE(mtr, 0x28, | |
| 1550 | (SAA7196_REG(mtr, 0x28) & ~0x0c)) ; | |
| 1551 | if(mtr->flags & METEOR_RGB){ | |
| 1552 | bt254_ntsc(mtr, 1); | |
| 1553 | } | |
| 1554 | break; | |
| 1555 | case METEOR_FMT_PAL: | |
| 1556 | mtr->flags = (mtr->flags & ~METEOR_FORM_MASK) | | |
| 1557 | METEOR_PAL; | |
| 1558 | SAA7196_WRITE(mtr, SAA7196_STDC, | |
| 1559 | (SAA7196_REG(mtr, SAA7196_STDC) & ~0x01)); | |
| 1560 | SAA7196_WRITE(mtr, 0x0f, | |
| 1561 | (SAA7196_REG(mtr, 0x0f) & ~0xe0)); | |
| 1562 | SAA7196_WRITE(mtr, 0x22, 0x00); | |
| 1563 | SAA7196_WRITE(mtr, 0x24, | |
| 1564 | (SAA7196_REG(mtr, 0x24) | 0x0c)); | |
| 1565 | SAA7196_WRITE(mtr, 0x26, 0x20); | |
| 1566 | SAA7196_WRITE(mtr, 0x28, | |
| 1567 | (SAA7196_REG(mtr, 0x28) & ~0x0c) | 0x04) ; | |
| 1568 | if(mtr->flags & METEOR_RGB){ | |
| 1569 | bt254_ntsc(mtr, 0); | |
| 1570 | } | |
| 1571 | break; | |
| 1572 | case METEOR_FMT_SECAM: | |
| 1573 | mtr->flags = (mtr->flags & ~METEOR_FORM_MASK) | | |
| 1574 | METEOR_SECAM; | |
| 1575 | SAA7196_WRITE(mtr, SAA7196_STDC, | |
| 1576 | (SAA7196_REG(mtr, SAA7196_STDC) & ~0x01) | 0x1); | |
| 1577 | SAA7196_WRITE(mtr, 0x0f, | |
| 1578 | (SAA7196_REG(mtr, 0x0f) & ~0xe0) | 0x20); | |
| 1579 | SAA7196_WRITE(mtr, 0x22, 0x00); | |
| 1580 | SAA7196_WRITE(mtr, 0x24, | |
| 1581 | (SAA7196_REG(mtr, 0x24) | 0x0c)); | |
| 1582 | SAA7196_WRITE(mtr, 0x26, 0x20); | |
| 1583 | SAA7196_WRITE(mtr, 0x28, | |
| 1584 | (SAA7196_REG(mtr, 0x28) & ~0x0c) | 0x04) ; | |
| 1585 | if(mtr->flags & METEOR_RGB){ | |
| 1586 | bt254_ntsc(mtr, 0); | |
| 1587 | } | |
| 1588 | break; | |
| 1589 | case METEOR_FMT_AUTOMODE: | |
| 1590 | mtr->flags = (mtr->flags & ~METEOR_FORM_MASK) | | |
| 1591 | METEOR_AUTOMODE; | |
| 1592 | SAA7196_WRITE(mtr, SAA7196_STDC, | |
| 1593 | (SAA7196_REG(mtr, SAA7196_STDC) & ~0x01)); | |
| 1594 | SAA7196_WRITE(mtr, 0x0f, | |
| 1595 | (SAA7196_REG(mtr, 0x0f) & ~0xe0) | 0x80); | |
| 1596 | break; | |
| 1597 | default: | |
| 1598 | return EINVAL; | |
| 1599 | } | |
| 1600 | break; | |
| 1601 | case METEORGFMT: /* get input format */ | |
| fef8985e | 1602 | *(u_long *)data = mtr->flags & METEOR_FORM_MASK; |
| 984263bc MD |
1603 | break; |
| 1604 | case METEORCAPTUR: | |
| 1605 | temp = mtr->flags; | |
| fef8985e | 1606 | switch (*(int *) data) { |
| 984263bc MD |
1607 | case METEOR_CAP_SINGLE: |
| 1608 | if (mtr->bigbuf==0) /* no frame buffer allocated */ | |
| 1609 | return(ENOMEM); | |
| 1610 | ||
| 1611 | if (temp & METEOR_CAP_MASK) | |
| 1612 | return(EIO); /* already capturing */ | |
| 1613 | ||
| 1614 | start_capture(mtr, METEOR_SINGLE); | |
| 1615 | ||
| 1616 | /* wait for capture to complete */ | |
| 1617 | error=tsleep((caddr_t)mtr, METPRI, "capturing", 0); | |
| 1618 | if(error) | |
| e3869ec7 | 1619 | kprintf("meteor%d: ioctl: tsleep error %d\n", |
| 984263bc MD |
1620 | unit, error); |
| 1621 | mtr->flags &= ~(METEOR_SINGLE|METEOR_WANT_MASK); | |
| 1622 | break; | |
| 1623 | case METEOR_CAP_CONTINOUS: | |
| 1624 | if (mtr->bigbuf==0) /* no frame buffer allocated */ | |
| 1625 | return(ENOMEM); | |
| 1626 | ||
| 1627 | if (temp & METEOR_CAP_MASK) | |
| 1628 | return(EIO); /* already capturing */ | |
| 1629 | ||
| 1630 | start_capture(mtr, METEOR_CONTIN); | |
| 1631 | ||
| 1632 | break; | |
| 1633 | case METEOR_CAP_STOP_CONT: | |
| 1634 | if (mtr->flags & METEOR_CONTIN) { | |
| 1635 | /* turn off capture */ | |
| 1636 | base->cap_cntl = 0x8ff0; | |
| 1637 | mtr->flags &= ~(METEOR_CONTIN|METEOR_WANT_MASK); | |
| 1638 | } | |
| 1639 | break; | |
| 1640 | ||
| 1641 | default: | |
| 1642 | error = EINVAL; | |
| 1643 | break; | |
| 1644 | } | |
| 1645 | break; | |
| 1646 | case METEORCAPFRM: | |
| fef8985e | 1647 | frame = (struct meteor_capframe *) data; |
| 984263bc MD |
1648 | if (!frame) |
| 1649 | return(EINVAL); | |
| 1650 | switch (frame->command) { | |
| 1651 | case METEOR_CAP_N_FRAMES: | |
| 1652 | if (mtr->flags & METEOR_CAP_MASK) | |
| 1653 | return(EIO); | |
| 1654 | if (mtr->flags & (METEOR_YUV_PLANAR | METEOR_YUV_422)) /* XXX */ | |
| 1655 | return(EINVAL); /* should fix intr so we allow these */ | |
| 1656 | if (mtr->bigbuf == 0) | |
| 1657 | return(ENOMEM); | |
| 1658 | if ((mtr->frames < 2) || | |
| 1659 | (frame->lowat < 1 || frame->lowat >= mtr->frames) || | |
| 1660 | (frame->hiwat < 1 || frame->hiwat >= mtr->frames) || | |
| 1661 | (frame->lowat > frame->hiwat)) | |
| 1662 | return(EINVAL); | |
| 1663 | /* meteor_mem structure is on the page after the data */ | |
| 1664 | mem = mtr->mem = (struct meteor_mem *) (mtr->bigbuf + | |
| 1665 | (round_page(mtr->frame_size * mtr->frames))); | |
| 1666 | mtr->current = 1; | |
| 1667 | mtr->synch_wait = 0; | |
| 1668 | mem->num_bufs = mtr->frames; | |
| 1669 | mem->frame_size= mtr->frame_size; | |
| 1670 | /* user and kernel change these */ | |
| 1671 | mem->lowat = frame->lowat; | |
| 1672 | mem->hiwat = frame->hiwat; | |
| 1673 | mem->active = 0; | |
| 1674 | mem->num_active_bufs = 0; | |
| 1675 | /* Start capture */ | |
| 1676 | start_capture(mtr, METEOR_SYNCAP); | |
| 1677 | break; | |
| 1678 | case METEOR_CAP_STOP_FRAMES: | |
| 1679 | if (mtr->flags & METEOR_SYNCAP) { | |
| 1680 | /* turn off capture */ | |
| 1681 | base->cap_cntl = 0x8ff0; | |
| 1682 | mtr->flags &= ~(METEOR_SYNCAP|METEOR_WANT_MASK); | |
| 1683 | } | |
| 1684 | break; | |
| 1685 | case METEOR_HALT_N_FRAMES: | |
| 1686 | if(mtr->flags & METEOR_SYNCAP) { | |
| 1687 | base->cap_cntl = 0x8ff0; | |
| 1688 | mtr->flags &= ~(METEOR_WANT_MASK); | |
| 1689 | } | |
| 1690 | break; | |
| 1691 | case METEOR_CONT_N_FRAMES: | |
| 1692 | if(!(mtr->flags & METEOR_SYNCAP)) { | |
| 1693 | error = EINVAL; | |
| 1694 | break; | |
| 1695 | } | |
| 1696 | start_capture(mtr, METEOR_SYNCAP); | |
| 1697 | break; | |
| 1698 | default: | |
| 1699 | error = EINVAL; | |
| 1700 | break; | |
| 1701 | } | |
| 1702 | break; | |
| 1703 | ||
| 1704 | case METEORSETGEO: | |
| fef8985e | 1705 | geo = (struct meteor_geomet *) data; |
| 984263bc MD |
1706 | |
| 1707 | /* Either even or odd, if even & odd, then these a zero */ | |
| 1708 | if((geo->oformat & METEOR_GEO_ODD_ONLY) && | |
| 1709 | (geo->oformat & METEOR_GEO_EVEN_ONLY)) { | |
| e3869ec7 | 1710 | kprintf("meteor%d: ioctl: Geometry odd or even only.\n", |
| 984263bc MD |
1711 | unit); |
| 1712 | return EINVAL; | |
| 1713 | } | |
| 1714 | /* set/clear even/odd flags */ | |
| 1715 | if(geo->oformat & METEOR_GEO_ODD_ONLY) | |
| 1716 | mtr->flags |= METEOR_ONLY_ODD_FIELDS; | |
| 1717 | else | |
| 1718 | mtr->flags &= ~METEOR_ONLY_ODD_FIELDS; | |
| 1719 | if(geo->oformat & METEOR_GEO_EVEN_ONLY) | |
| 1720 | mtr->flags |= METEOR_ONLY_EVEN_FIELDS; | |
| 1721 | else | |
| 1722 | mtr->flags &= ~METEOR_ONLY_EVEN_FIELDS; | |
| 1723 | ||
| 1724 | /* can't change parameters while capturing */ | |
| 1725 | if (mtr->flags & METEOR_CAP_MASK) | |
| 1726 | return(EBUSY); | |
| 1727 | ||
| 1728 | if ((geo->columns & 0x3fe) != geo->columns) { | |
| e3869ec7 | 1729 | kprintf( |
| 984263bc MD |
1730 | "meteor%d: ioctl: %d: columns too large or not even.\n", |
| 1731 | unit, geo->columns); | |
| 1732 | error = EINVAL; | |
| 1733 | } | |
| 1734 | if (((geo->rows & 0x7fe) != geo->rows) || | |
| 1735 | ((geo->oformat & METEOR_GEO_FIELD_MASK) && | |
| 1736 | ((geo->rows & 0x3fe) != geo->rows)) ) { | |
| e3869ec7 | 1737 | kprintf( |
| 984263bc MD |
1738 | "meteor%d: ioctl: %d: rows too large or not even.\n", |
| 1739 | unit, geo->rows); | |
| 1740 | error = EINVAL; | |
| 1741 | } | |
| 1742 | if (geo->frames > 32) { | |
| e3869ec7 | 1743 | kprintf("meteor%d: ioctl: too many frames.\n", unit); |
| 984263bc MD |
1744 | error = EINVAL; |
| 1745 | } | |
| 1746 | if(error) return error; | |
| 1747 | ||
| 1748 | if ((temp=geo->rows * geo->columns * geo->frames * 2) != 0) { | |
| 1749 | if (geo->oformat & METEOR_GEO_RGB24) temp = temp * 2; | |
| 1750 | ||
| 1751 | /* meteor_mem structure for SYNC Capture */ | |
| 1752 | if (geo->frames > 1) temp += PAGE_SIZE; | |
| 1753 | ||
| 1754 | temp = btoc(temp); | |
| 1755 | if (temp > mtr->alloc_pages | |
| 1756 | #ifdef METEOR_TEST_VIDEO | |
| 1757 | && mtr->video.addr == 0 | |
| 1758 | #endif | |
| 1759 | ) { | |
| 1760 | buf = get_meteor_mem(unit, temp*PAGE_SIZE); | |
| 1761 | if(buf != 0) { | |
| e4846942 | 1762 | kmem_free(&kernel_map, mtr->bigbuf, |
| 984263bc MD |
1763 | (mtr->alloc_pages * PAGE_SIZE)); |
| 1764 | mtr->bigbuf = buf; | |
| 1765 | mtr->alloc_pages = temp; | |
| 1766 | if(bootverbose) | |
| e3869ec7 | 1767 | kprintf( |
| 984263bc MD |
1768 | "meteor%d: ioctl: Allocating %d bytes\n", |
| 1769 | unit, temp*PAGE_SIZE); | |
| 1770 | } else { | |
| 1771 | error = ENOMEM; | |
| 1772 | } | |
| 1773 | } | |
| 1774 | } | |
| 1775 | if(error) return error; | |
| 1776 | ||
| 1777 | mtr->rows = geo->rows; | |
| 1778 | mtr->cols = geo->columns; | |
| 1779 | mtr->frames = geo->frames; | |
| 1780 | ||
| 1781 | #ifdef METEOR_TEST_VIDEO | |
| 1782 | if(mtr->video.addr) | |
| 1783 | buf = vtophys(mtr->video.addr); | |
| 1784 | else | |
| 1785 | #endif | |
| 1786 | buf = vtophys(mtr->bigbuf); | |
| 1787 | ||
| 1788 | /* set defaults and end of buffer locations */ | |
| 1789 | base->dma1e = buf; | |
| 1790 | base->dma2e = buf; | |
| 1791 | base->dma3e = buf; | |
| 1792 | base->dma1o = buf; | |
| 1793 | base->dma2o = buf; | |
| 1794 | base->dma3o = buf; | |
| 1795 | base->stride1e = 0; | |
| 1796 | base->stride2e = 0; | |
| 1797 | base->stride3e = 0; | |
| 1798 | base->stride1o = 0; | |
| 1799 | base->stride2o = 0; | |
| 1800 | base->stride3o = 0; | |
| 1801 | /* set end of DMA location, even/odd */ | |
| 1802 | base->dma_end_e = | |
| 1803 | base->dma_end_o = buf + mtr->alloc_pages * PAGE_SIZE; | |
| 1804 | ||
| 1805 | /* | |
| 1806 | * Determine if we can use the hardware range detect. | |
| 1807 | */ | |
| 1808 | if(mtr->alloc_pages * PAGE_SIZE < RANGE_BOUNDARY && | |
| 1809 | ((buf & 0xff000000) | base->dma_end_e) == | |
| 1810 | (buf + mtr->alloc_pages * PAGE_SIZE) ) | |
| 1811 | mtr->range_enable = 0x8000; | |
| 1812 | else { | |
| 1813 | mtr->range_enable = 0x0; | |
| 1814 | base->dma_end_e = | |
| 1815 | base->dma_end_o = 0xffffffff; | |
| 1816 | } | |
| 1817 | ||
| 1818 | ||
| 1819 | switch (geo->oformat & METEOR_GEO_OUTPUT_MASK) { | |
| 1820 | case 0: /* default */ | |
| 1821 | case METEOR_GEO_RGB16: | |
| 1822 | mtr->depth = 2; | |
| 1823 | mtr->frame_size = mtr->rows * mtr->cols * mtr->depth; | |
| 1824 | mtr->flags &= ~METEOR_OUTPUT_FMT_MASK; | |
| 1825 | mtr->flags |= METEOR_RGB16; | |
| 1826 | temp = mtr->cols * mtr->depth; | |
| 1827 | /* recal stride and starting point */ | |
| 1828 | switch(mtr->flags & METEOR_ONLY_FIELDS_MASK) { | |
| 1829 | case METEOR_ONLY_ODD_FIELDS: | |
| 1830 | base->dma1o = buf; | |
| 1831 | #ifdef METEOR_TEST_VIDEO | |
| 1832 | if(mtr->video.addr && mtr->video.width) | |
| 1833 | base->stride1o = mtr->video.width-temp; | |
| 1834 | #endif | |
| 1835 | SAA7196_WRITE(mtr, 0x20, 0xd0); | |
| 1836 | break; | |
| 1837 | case METEOR_ONLY_EVEN_FIELDS: | |
| 1838 | base->dma1e = buf; | |
| 1839 | #ifdef METEOR_TEST_VIDEO | |
| 1840 | if(mtr->video.addr && mtr->video.width) | |
| 1841 | base->stride1e = mtr->video.width-temp; | |
| 1842 | #endif | |
| 1843 | SAA7196_WRITE(mtr, 0x20, 0xf0); | |
| 1844 | break; | |
| 1845 | default: /* interlaced even/odd */ | |
| 1846 | base->dma1e = buf; | |
| 1847 | base->dma1o = buf + temp; | |
| 1848 | base->stride1e = base->stride1o = temp; | |
| 1849 | #ifdef METEOR_TEST_VIDEO | |
| 1850 | if(mtr->video.addr && mtr->video.width) { | |
| 1851 | base->dma1o = buf + mtr->video.width; | |
| 1852 | base->stride1e = base->stride1o = | |
| 1853 | mtr->video.width - | |
| 1854 | temp + mtr->video.width; | |
| 1855 | } | |
| 1856 | #endif | |
| 1857 | SAA7196_WRITE(mtr, 0x20, 0x90); | |
| 1858 | break; | |
| 1859 | } | |
| 1860 | base->routee = base->routeo = 0xeeeeee01; | |
| 1861 | break; | |
| 1862 | case METEOR_GEO_RGB24: | |
| 1863 | mtr->depth = 4; | |
| 1864 | mtr->frame_size = mtr->rows * mtr->cols * mtr->depth; | |
| 1865 | mtr->flags &= ~METEOR_OUTPUT_FMT_MASK; | |
| 1866 | mtr->flags |= METEOR_RGB24; | |
| 1867 | temp = mtr->cols * mtr->depth; | |
| 1868 | /* recal stride and starting point */ | |
| 1869 | switch(mtr->flags & METEOR_ONLY_FIELDS_MASK) { | |
| 1870 | case METEOR_ONLY_ODD_FIELDS: | |
| 1871 | base->dma1o = buf; | |
| 1872 | #ifdef METEOR_TEST_VIDEO | |
| 1873 | if(mtr->video.addr && mtr->video.width) | |
| 1874 | base->stride1o = mtr->video.width-temp; | |
| 1875 | #endif | |
| 1876 | SAA7196_WRITE(mtr, 0x20, 0xd2); | |
| 1877 | break; | |
| 1878 | case METEOR_ONLY_EVEN_FIELDS: | |
| 1879 | base->dma1e = buf; | |
| 1880 | #ifdef METEOR_TEST_VIDEO | |
| 1881 | if(mtr->video.addr && mtr->video.width) | |
| 1882 | base->stride1e = mtr->video.width-temp; | |
| 1883 | #endif | |
| 1884 | SAA7196_WRITE(mtr, 0x20, 0xf2); | |
| 1885 | break; | |
| 1886 | default: /* interlaced even/odd */ | |
| 1887 | base->dma1e = buf; | |
| 1888 | base->dma1o = buf + mtr->cols * mtr->depth; | |
| 1889 | base->stride1e = base->stride1o = | |
| 1890 | mtr->cols * mtr->depth; | |
| 1891 | #ifdef METEOR_TEST_VIDEO | |
| 1892 | if(mtr->video.addr && mtr->video.width) { | |
| 1893 | base->dma1o = buf + mtr->video.width; | |
| 1894 | base->stride1e = base->stride1o = | |
| 1895 | mtr->video.width - | |
| 1896 | temp + mtr->video.width; | |
| 1897 | } | |
| 1898 | #endif | |
| 1899 | SAA7196_WRITE(mtr, 0x20, 0x92); | |
| 1900 | break; | |
| 1901 | } | |
| 1902 | base->routee= base->routeo= 0x39393900; | |
| 1903 | break; | |
| 1904 | case METEOR_GEO_YUV_PLANAR: | |
| 1905 | mtr->depth = 2; | |
| 1906 | temp = mtr->rows * mtr->cols; /* compute frame size */ | |
| 1907 | mtr->frame_size = temp * mtr->depth; | |
| 1908 | mtr->flags &= ~METEOR_OUTPUT_FMT_MASK; | |
| 1909 | mtr->flags |= METEOR_YUV_PLANAR; | |
| 1910 | /* recal stride and starting point */ | |
| 1911 | switch(mtr->flags & METEOR_ONLY_FIELDS_MASK) { | |
| 1912 | case METEOR_ONLY_ODD_FIELDS: | |
| 1913 | base->dma1o = buf; /* Y Odd */ | |
| 1914 | base->dma2o = buf + temp; /* U Odd */ | |
| 1915 | temp >>= 1; | |
| 1916 | base->dma3o = base->dma2o + temp; /* V Odd */ | |
| 1917 | SAA7196_WRITE(mtr, 0x20, 0xd1); | |
| 1918 | break; | |
| 1919 | case METEOR_ONLY_EVEN_FIELDS: | |
| 1920 | base->dma1e = buf; /* Y Even */ | |
| 1921 | base->dma2e = buf + temp; /* U Even */ | |
| 1922 | temp >>= 1; | |
| 1923 | base->dma2e= base->dma2e + temp; /* V Even */ | |
| 1924 | SAA7196_WRITE(mtr, 0x20, 0xf1); | |
| 1925 | break; | |
| 1926 | default: /* interlaced even/odd */ | |
| 1927 | base->dma1e = buf; /* Y Even */ | |
| 1928 | base->dma2e = buf + temp; /* U Even */ | |
| 1929 | temp >>= 2; | |
| 1930 | base->dma3e = base->dma2e + temp; /* V Even */ | |
| 1931 | base->dma1o = base->dma1e+mtr->cols;/* Y Odd */ | |
| 1932 | base->dma2o = base->dma3e + temp; /* U Odd */ | |
| 1933 | base->dma3o = base->dma2o + temp; /* V Odd */ | |
| 1934 | base->stride1e = base->stride1o = mtr->cols; | |
| 1935 | SAA7196_WRITE(mtr, 0x20, 0x91); | |
| 1936 | break; | |
| 1937 | } | |
| 1938 | switch (geo->oformat & | |
| 1939 | (METEOR_GEO_YUV_12 | METEOR_GEO_YUV_9)) { | |
| 1940 | case METEOR_GEO_YUV_9: | |
| 1941 | base->routee=base->routeo = 0xaaaaffc3; | |
| 1942 | break; | |
| 1943 | case METEOR_GEO_YUV_12: | |
| 1944 | base->routee=base->routeo = 0xaaaaffc2; | |
| 1945 | break; | |
| 1946 | default: | |
| 1947 | base->routee=base->routeo = 0xaaaaffc1; | |
| 1948 | break; | |
| 1949 | } | |
| 1950 | break; | |
| 1951 | case METEOR_GEO_YUV_422:/* same as planer, different uv order */ | |
| 1952 | mtr->depth = 2; | |
| 1953 | temp = mtr->rows * mtr->cols; /* compute frame size */ | |
| 1954 | mtr->frame_size = temp * mtr->depth; | |
| 1955 | mtr->flags &= ~METEOR_OUTPUT_FMT_MASK; | |
| 1956 | mtr->flags |= METEOR_YUV_422; | |
| 1957 | switch(mtr->flags & METEOR_ONLY_FIELDS_MASK) { | |
| 1958 | case METEOR_ONLY_ODD_FIELDS: | |
| 1959 | base->dma1o = buf; | |
| 1960 | base->dma2o = buf + temp; | |
| 1961 | base->dma3o = base->dma2o + (temp >> 1); | |
| 1962 | SAA7196_WRITE(mtr, 0x20, 0xd1); | |
| 1963 | break; | |
| 1964 | case METEOR_ONLY_EVEN_FIELDS: | |
| 1965 | base->dma1e = buf; | |
| 1966 | base->dma2e = buf + temp; | |
| 1967 | base->dma3e = base->dma2e + (temp >> 1); | |
| 1968 | SAA7196_WRITE(mtr, 0x20, 0xf1); | |
| 1969 | break; | |
| 1970 | default: /* interlaced even/odd */ | |
| 1971 | base->dma1e = buf; /* Y even */ | |
| 1972 | base->dma2e = buf + temp; /* U even */ | |
| 1973 | base->dma3e = | |
| 1974 | base->dma2e + (temp >> 1);/* V even */ | |
| 1975 | base->dma1o = base->dma1e+mtr->cols;/* Y odd */ | |
| 1976 | temp = mtr->cols >> 1; | |
| 1977 | base->dma2o = base->dma2e+temp; /* U odd */ | |
| 1978 | base->dma3o = base->dma3e+temp; /* V odd */ | |
| 1979 | base->stride1e = | |
| 1980 | base->stride1o = mtr->cols; /* Y stride */ | |
| 1981 | base->stride2e = | |
| 1982 | base->stride2o = temp; /* U stride */ | |
| 1983 | base->stride3e = | |
| 1984 | base->stride3o = temp; /* V stride */ | |
| 1985 | SAA7196_WRITE(mtr, 0x20, 0x91); | |
| 1986 | break; | |
| 1987 | } | |
| 1988 | switch (geo->oformat & | |
| 1989 | (METEOR_GEO_YUV_12 | METEOR_GEO_YUV_9)) { | |
| 1990 | case METEOR_GEO_YUV_9: | |
| 1991 | base->routee=base->routeo = 0xaaaaffc3; | |
| 1992 | break; | |
| 1993 | case METEOR_GEO_YUV_12: | |
| 1994 | base->routee=base->routeo = 0xaaaaffc2; | |
| 1995 | break; | |
| 1996 | default: | |
| 1997 | base->routee=base->routeo = 0xaaaaffc1; | |
| 1998 | break; | |
| 1999 | } | |
| 2000 | break; | |
| 2001 | case METEOR_GEO_YUV_PACKED: | |
| 2002 | mtr->depth = 2; | |
| 2003 | mtr->frame_size = mtr->rows * mtr->cols * mtr->depth; | |
| 2004 | mtr->flags &= ~METEOR_OUTPUT_FMT_MASK; | |
| 2005 | mtr->flags |= METEOR_YUV_PACKED; | |
| 2006 | /* recal stride and odd starting point */ | |
| 2007 | switch(mtr->flags & METEOR_ONLY_FIELDS_MASK) { | |
| 2008 | case METEOR_ONLY_ODD_FIELDS: | |
| 2009 | base->dma1o = buf; | |
| 2010 | SAA7196_WRITE(mtr, 0x20, 0xd1); | |
| 2011 | break; | |
| 2012 | case METEOR_ONLY_EVEN_FIELDS: | |
| 2013 | base->dma1e = buf; | |
| 2014 | SAA7196_WRITE(mtr, 0x20, 0xf1); | |
| 2015 | break; | |
| 2016 | default: /* interlaced even/odd */ | |
| 2017 | base->dma1e = buf; | |
| 2018 | base->dma1o = buf + mtr->cols * mtr->depth; | |
| 2019 | base->stride1e = base->stride1o = | |
| 2020 | mtr->cols * mtr->depth; | |
| 2021 | SAA7196_WRITE(mtr, 0x20, 0x91); | |
| 2022 | break; | |
| 2023 | } | |
| 2024 | base->routee = base->routeo = 0xeeeeee41; | |
| 2025 | break; | |
| 2026 | default: | |
| 2027 | error = EINVAL; /* invalid argument */ | |
| e3869ec7 | 2028 | kprintf("meteor%d: ioctl: invalid output format\n",unit); |
| 984263bc MD |
2029 | break; |
| 2030 | } | |
| 2031 | /* set cols */ | |
| 2032 | SAA7196_WRITE(mtr, 0x21, mtr->cols & 0xff); | |
| 2033 | SAA7196_WRITE(mtr, 0x24, | |
| 2034 | ((SAA7196_REG(mtr, 0x24) & ~0x03) | | |
| 2035 | ((mtr->cols >> 8) & 0x03))); | |
| 2036 | /* set rows */ | |
| 2037 | if(mtr->flags & METEOR_ONLY_FIELDS_MASK) { | |
| 2038 | SAA7196_WRITE(mtr, 0x25, ((mtr->rows) & 0xff)); | |
| 2039 | SAA7196_WRITE(mtr, 0x28, | |
| 2040 | ((SAA7196_REG(mtr, 0x28) & ~0x03) | | |
| 2041 | ((mtr->rows >> 8) & 0x03))); | |
| 2042 | } else { /* Interlaced */ | |
| 2043 | SAA7196_WRITE(mtr, 0x25, ((mtr->rows >> 1) & 0xff)); | |
| 2044 | SAA7196_WRITE(mtr, 0x28, | |
| 2045 | ((SAA7196_REG(mtr, 0x28) & ~0x03) | | |
| 2046 | ((mtr->rows >> 9) & 0x03))); | |
| 2047 | } | |
| 2048 | /* set signed/unsigned chrominance */ | |
| 2049 | SAA7196_WRITE(mtr, 0x30, (SAA7196_REG(mtr, 0x30) & ~0x10) | | |
| 2050 | ((geo->oformat&METEOR_GEO_UNSIGNED)?0:0x10)); | |
| 2051 | break; | |
| 2052 | case METEORGETGEO: | |
| fef8985e | 2053 | geo = (struct meteor_geomet *) data; |
| 984263bc MD |
2054 | geo->rows = mtr->rows; |
| 2055 | geo->columns = mtr->cols; | |
| 2056 | geo->frames = mtr->frames; | |
| 2057 | geo->oformat = (mtr->flags & METEOR_OUTPUT_FMT_MASK) | | |
| 2058 | (mtr->flags & METEOR_ONLY_FIELDS_MASK) | | |
| 2059 | (SAA7196_REG(mtr, 0x30) & 0x10 ? | |
| 2060 | 0:METEOR_GEO_UNSIGNED); | |
| 2061 | switch(base->routee & 0xff) { | |
| 2062 | case 0xc3: | |
| 2063 | geo->oformat |= METEOR_GEO_YUV_9; | |
| 2064 | break; | |
| 2065 | case 0xc2: | |
| 2066 | geo->oformat |= METEOR_GEO_YUV_12; | |
| 2067 | break; | |
| 2068 | default: | |
| 2069 | break; | |
| 2070 | } | |
| 2071 | break; | |
| 2072 | case METEORSCOUNT: /* (re)set error counts */ | |
| fef8985e | 2073 | cnt = (struct meteor_counts *) data; |
| 984263bc MD |
2074 | mtr->fifo_errors = cnt->fifo_errors; |
| 2075 | mtr->dma_errors = cnt->dma_errors; | |
| 2076 | mtr->frames_captured = cnt->frames_captured; | |
| 2077 | mtr->even_fields_captured = cnt->even_fields_captured; | |
| 2078 | mtr->odd_fields_captured = cnt->odd_fields_captured; | |
| 2079 | break; | |
| 2080 | case METEORGCOUNT: /* get error counts */ | |
| fef8985e | 2081 | cnt = (struct meteor_counts *) data; |
| 984263bc MD |
2082 | cnt->fifo_errors = mtr->fifo_errors; |
| 2083 | cnt->dma_errors = mtr->dma_errors; | |
| 2084 | cnt->frames_captured = mtr->frames_captured; | |
| 2085 | cnt->even_fields_captured = mtr->even_fields_captured; | |
| 2086 | cnt->odd_fields_captured = mtr->odd_fields_captured; | |
| 2087 | break; | |
| 2088 | default: | |
| e3869ec7 | 2089 | kprintf("meteor%d: ioctl: invalid ioctl request\n", unit); |
| 984263bc MD |
2090 | error = ENOTTY; |
| 2091 | break; | |
| 2092 | } | |
| 2093 | return(error); | |
| 2094 | } | |
| 2095 | ||
| 2096 | int | |
| fef8985e | 2097 | meteor_mmap(struct dev_mmap_args *ap) |
| 984263bc | 2098 | { |
| b13267a5 | 2099 | cdev_t dev = ap->a_head.a_dev; |
| 984263bc MD |
2100 | int unit; |
| 2101 | meteor_reg_t *mtr; | |
| 2102 | ||
| 2103 | unit = UNIT(minor(dev)); | |
| 2104 | if (unit >= NMETEOR) /* at this point could this happen? */ | |
| 2105 | return(-1); | |
| 2106 | ||
| 2107 | mtr = &(meteor[unit]); | |
| 2108 | ||
| 2109 | ||
| fef8985e | 2110 | if (ap->a_nprot & PROT_EXEC) |
| 984263bc MD |
2111 | return -1; |
| 2112 | ||
| fef8985e | 2113 | if (ap->a_offset >= mtr->alloc_pages * PAGE_SIZE) |
| 984263bc MD |
2114 | return -1; |
| 2115 | ||
| fef8985e | 2116 | return i386_btop(vtophys(mtr->bigbuf) + ap->a_offset); |
| 984263bc | 2117 | } |