2 planb - PlanB frame grabber driver
4 PlanB is used in the 7x00/8x00 series of PowerMacintosh
5 Computers as video input DMA controller.
7 Copyright (C) 1998 Michel Lanners (mlan@cpu.lu)
9 Based largely on the bttv driver by Ralph Metzler (rjkm@thp.uni-koeln.de)
11 Additional debugging and coding by Takashi Oe (toe@unlserve.unl.edu)
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2 of the License, or
16 (at your option) any later version.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 /* $Id: planb.c,v 1.18 1999/05/02 17:36:34 mlan Exp $ */
30 #include <linux/init.h>
31 #include <linux/errno.h>
32 #include <linux/module.h>
33 #include <linux/kernel.h>
34 #include <linux/major.h>
35 #include <linux/slab.h>
36 #include <linux/types.h>
37 #include <linux/pci.h>
38 #include <linux/delay.h>
39 #include <linux/vmalloc.h>
41 #include <linux/sched.h>
42 #include <linux/videodev.h>
43 #include <linux/wait.h>
44 #include <asm/uaccess.h>
47 #include <asm/dbdma.h>
48 #include <asm/pgtable.h>
51 #include <asm/semaphore.h>
56 /* Would you mind for some ugly debugging? */
58 #define DEBUG(x...) printk(KERN_DEBUG ## x) /* Debug driver */
60 #define DEBUG(x...) /* Don't debug driver */
64 #define IDEBUG(x...) printk(KERN_DEBUG ## x) /* Debug interrupt part */
66 #define IDEBUG(x...) /* Don't debug interrupt part */
69 /* Ever seen a Mac with more than 1 of these? */
73 static struct planb planbs
[PLANB_MAX
];
74 static volatile struct planb_registers
*planb_regs
;
76 static int def_norm
= PLANB_DEF_NORM
; /* default norm */
77 static int video_nr
= -1;
79 MODULE_PARM(def_norm
, "i");
80 MODULE_PARM_DESC(def_norm
, "Default startup norm (0=PAL, 1=NTSC, 2=SECAM)");
81 MODULE_PARM(video_nr
,"i");
82 MODULE_LICENSE("GPL");
85 /* ------------------ PlanB Exported Functions ------------------ */
86 static long planb_write(struct video_device
*, const char *, unsigned long, int);
87 static long planb_read(struct video_device
*, char *, unsigned long, int);
88 static int planb_open(struct video_device
*, int);
89 static void planb_close(struct video_device
*);
90 static int planb_ioctl(struct video_device
*, unsigned int, void *);
91 static int planb_init_done(struct video_device
*);
92 static int planb_mmap(struct video_device
*, const char *, unsigned long);
93 static void planb_irq(int, void *, struct pt_regs
*);
94 static void release_planb(void);
95 int init_planbs(struct video_init
*);
97 /* ------------------ PlanB Internal Functions ------------------ */
98 static int planb_prepare_open(struct planb
*);
99 static void planb_prepare_close(struct planb
*);
100 static void saa_write_reg(unsigned char, unsigned char);
101 static unsigned char saa_status(int, struct planb
*);
102 static void saa_set(unsigned char, unsigned char, struct planb
*);
103 static void saa_init_regs(struct planb
*);
104 static int grabbuf_alloc(struct planb
*);
105 static int vgrab(struct planb
*, struct video_mmap
*);
106 static void add_clip(struct planb
*, struct video_clip
*);
107 static void fill_cmd_buff(struct planb
*);
108 static void cmd_buff(struct planb
*);
109 static volatile struct dbdma_cmd
*setup_grab_cmd(int, struct planb
*);
110 static void overlay_start(struct planb
*);
111 static void overlay_stop(struct planb
*);
112 static inline void tab_cmd_dbdma(volatile struct dbdma_cmd
*, unsigned short,
114 static inline void tab_cmd_store(volatile struct dbdma_cmd
*, unsigned int,
116 static inline void tab_cmd_gen(volatile struct dbdma_cmd
*, unsigned short,
117 unsigned short, unsigned int, unsigned int);
118 static int init_planb(struct planb
*);
119 static int find_planb(void);
120 static void planb_pre_capture(int, int, struct planb
*);
121 static volatile struct dbdma_cmd
*cmd_geo_setup(volatile struct dbdma_cmd
*,
122 int, int, int, int, int, struct planb
*);
123 static inline void planb_dbdma_stop(volatile struct dbdma_regs
*);
124 static unsigned int saa_geo_setup(int, int, int, int, struct planb
*);
125 static inline int overlay_is_active(struct planb
*);
127 /*******************************/
128 /* Memory management functions */
129 /*******************************/
131 static int grabbuf_alloc(struct planb
*pb
)
135 npage
= MAX_GBUFFERS
* ((PLANB_MAX_FBUF
/ PAGE_SIZE
+ 1)
136 #ifndef PLANB_GSCANLINE
138 #endif /* PLANB_GSCANLINE */
140 if ((pb
->rawbuf
= (unsigned char**) kmalloc (npage
141 * sizeof(unsigned long), GFP_KERNEL
)) == 0)
143 for (i
= 0; i
< npage
; i
++) {
144 pb
->rawbuf
[i
] = (unsigned char *)__get_free_pages(GFP_KERNEL
148 SetPageReserved(virt_to_page(pb
->rawbuf
[i
]));
151 printk(KERN_DEBUG
"PlanB: init_grab: grab buffer not allocated\n");
153 ClearPageReserved(virt_to_page(pb
->rawbuf
[i
]));
154 free_pages((unsigned long)pb
->rawbuf
[i
], 0);
159 pb
->rawbuf_size
= npage
;
163 /*****************************/
164 /* Hardware access functions */
165 /*****************************/
167 static void saa_write_reg(unsigned char addr
, unsigned char val
)
169 planb_regs
->saa_addr
= addr
; eieio();
170 planb_regs
->saa_regval
= val
; eieio();
174 /* return status byte 0 or 1: */
175 static unsigned char saa_status(int byte
, struct planb
*pb
)
177 saa_regs
[pb
->win
.norm
][SAA7196_STDC
] =
178 (saa_regs
[pb
->win
.norm
][SAA7196_STDC
] & ~2) | ((byte
& 1) << 1);
179 saa_write_reg (SAA7196_STDC
, saa_regs
[pb
->win
.norm
][SAA7196_STDC
]);
181 /* Let's wait 30msec for this one */
182 msleep_interruptible(30);
184 return (unsigned char)in_8 (&planb_regs
->saa_status
);
187 static void saa_set(unsigned char addr
, unsigned char val
, struct planb
*pb
)
189 if(saa_regs
[pb
->win
.norm
][addr
] != val
) {
190 saa_regs
[pb
->win
.norm
][addr
] = val
;
191 saa_write_reg (addr
, val
);
196 static void saa_init_regs(struct planb
*pb
)
200 for (i
= 0; i
< SAA7196_NUMREGS
; i
++)
201 saa_write_reg (i
, saa_regs
[pb
->win
.norm
][i
]);
204 static unsigned int saa_geo_setup(int width
, int height
, int interlace
, int bpp
,
207 int ht
, norm
= pb
->win
.norm
;
211 /* RGB555+a 1x16-bit + 16-bit transparent */
212 saa_regs
[norm
][SAA7196_FMTS
] &= ~0x3;
216 /* RGB888 1x24-bit + 8-bit transparent */
217 saa_regs
[norm
][SAA7196_FMTS
] &= ~0x1;
218 saa_regs
[norm
][SAA7196_FMTS
] |= 0x2;
223 ht
= (interlace
? height
/ 2 : height
);
224 saa_regs
[norm
][SAA7196_OUTPIX
] = (unsigned char) (width
& 0x00ff);
225 saa_regs
[norm
][SAA7196_HFILT
] = (saa_regs
[norm
][SAA7196_HFILT
] & ~0x3)
226 | (width
>> 8 & 0x3);
227 saa_regs
[norm
][SAA7196_OUTLINE
] = (unsigned char) (ht
& 0xff);
228 saa_regs
[norm
][SAA7196_VYP
] = (saa_regs
[norm
][SAA7196_VYP
] & ~0x3)
230 /* feed both fields if interlaced, or else feed only even fields */
231 saa_regs
[norm
][SAA7196_FMTS
] = (interlace
) ?
232 (saa_regs
[norm
][SAA7196_FMTS
] & ~0x60)
233 : (saa_regs
[norm
][SAA7196_FMTS
] | 0x60);
234 /* transparent mode; extended format enabled */
235 saa_regs
[norm
][SAA7196_DPATH
] |= 0x3;
240 /***************************/
241 /* DBDMA support functions */
242 /***************************/
244 static inline void planb_dbdma_restart(volatile struct dbdma_regs
*ch
)
246 out_le32(&ch
->control
, PLANB_CLR(RUN
));
247 out_le32(&ch
->control
, PLANB_SET(RUN
|WAKE
) | PLANB_CLR(PAUSE
));
250 static inline void planb_dbdma_stop(volatile struct dbdma_regs
*ch
)
254 out_le32(&ch
->control
, PLANB_CLR(RUN
) | PLANB_SET(FLUSH
));
255 while((in_le32(&ch
->status
) == (ACTIVE
| FLUSH
)) && (i
< 999)) {
256 IDEBUG("PlanB: waiting for DMA to stop\n");
261 static inline void tab_cmd_dbdma(volatile struct dbdma_cmd
*ch
,
262 unsigned short command
, unsigned int cmd_dep
)
264 st_le16(&ch
->command
, command
);
265 st_le32(&ch
->cmd_dep
, cmd_dep
);
268 static inline void tab_cmd_store(volatile struct dbdma_cmd
*ch
,
269 unsigned int phy_addr
, unsigned int cmd_dep
)
271 st_le16(&ch
->command
, STORE_WORD
| KEY_SYSTEM
);
272 st_le16(&ch
->req_count
, 4);
273 st_le32(&ch
->phy_addr
, phy_addr
);
274 st_le32(&ch
->cmd_dep
, cmd_dep
);
277 static inline void tab_cmd_gen(volatile struct dbdma_cmd
*ch
,
278 unsigned short command
, unsigned short req_count
,
279 unsigned int phy_addr
, unsigned int cmd_dep
)
281 st_le16(&ch
->command
, command
);
282 st_le16(&ch
->req_count
, req_count
);
283 st_le32(&ch
->phy_addr
, phy_addr
);
284 st_le32(&ch
->cmd_dep
, cmd_dep
);
287 static volatile struct dbdma_cmd
*cmd_geo_setup(
288 volatile struct dbdma_cmd
*c1
, int width
, int height
, int interlace
,
289 int bpp
, int clip
, struct planb
*pb
)
291 int norm
= pb
->win
.norm
;
293 if((saa_geo_setup(width
, height
, interlace
, bpp
, pb
)) != 0)
294 return (volatile struct dbdma_cmd
*)NULL
;
295 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->saa_addr
),
297 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->saa_regval
),
298 saa_regs
[norm
][SAA7196_FMTS
]);
299 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->saa_addr
),
301 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->saa_regval
),
302 saa_regs
[norm
][SAA7196_DPATH
]);
303 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->even
),
304 bpp
| ((clip
)? PLANB_CLIPMASK
: 0));
305 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->odd
),
306 bpp
| ((clip
)? PLANB_CLIPMASK
: 0));
307 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->saa_addr
),
309 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->saa_regval
),
310 saa_regs
[norm
][SAA7196_OUTPIX
]);
311 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->saa_addr
),
313 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->saa_regval
),
314 saa_regs
[norm
][SAA7196_HFILT
]);
315 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->saa_addr
),
317 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->saa_regval
),
318 saa_regs
[norm
][SAA7196_OUTLINE
]);
319 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->saa_addr
),
321 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->saa_regval
),
322 saa_regs
[norm
][SAA7196_VYP
]);
326 /******************************/
327 /* misc. supporting functions */
328 /******************************/
330 static inline void planb_lock(struct planb
*pb
)
335 static inline void planb_unlock(struct planb
*pb
)
344 static int planb_prepare_open(struct planb
*pb
)
348 /* allocate memory for two plus alpha command buffers (size: max lines,
349 plus 40 commands handling, plus 1 alignment), plus dummy command buf,
350 plus clipmask buffer, plus frame grabbing status */
351 size
= (pb
->tab_size
*(2+MAX_GBUFFERS
*TAB_FACTOR
)+1+MAX_GBUFFERS
352 * PLANB_DUMMY
)*sizeof(struct dbdma_cmd
)
353 +(PLANB_MAXLINES
*((PLANB_MAXPIXELS
+7)& ~7))/8
354 +MAX_GBUFFERS
*sizeof(unsigned int);
355 if ((pb
->priv_space
= kmalloc (size
, GFP_KERNEL
)) == 0)
357 memset ((void *) pb
->priv_space
, 0, size
);
358 pb
->overlay_last1
= pb
->ch1_cmd
= (volatile struct dbdma_cmd
*)
359 DBDMA_ALIGN (pb
->priv_space
);
360 pb
->overlay_last2
= pb
->ch2_cmd
= pb
->ch1_cmd
+ pb
->tab_size
;
361 pb
->ch1_cmd_phys
= virt_to_bus(pb
->ch1_cmd
);
362 pb
->cap_cmd
[0] = pb
->ch2_cmd
+ pb
->tab_size
;
363 pb
->pre_cmd
[0] = pb
->cap_cmd
[0] + pb
->tab_size
* TAB_FACTOR
;
364 for (i
= 1; i
< MAX_GBUFFERS
; i
++) {
365 pb
->cap_cmd
[i
] = pb
->pre_cmd
[i
-1] + PLANB_DUMMY
;
366 pb
->pre_cmd
[i
] = pb
->cap_cmd
[i
] + pb
->tab_size
* TAB_FACTOR
;
368 pb
->frame_stat
=(volatile unsigned int *)(pb
->pre_cmd
[MAX_GBUFFERS
-1]
370 pb
->mask
= (unsigned char *)(pb
->frame_stat
+MAX_GBUFFERS
);
375 for (i
= 0; i
< MAX_GBUFFERS
; i
++) {
376 pb
->frame_stat
[i
] = GBUFFER_UNUSED
;
380 pb
->gnorm_switch
[i
] = 0;
381 #ifndef PLANB_GSCANLINE
384 #endif /* PLANB_GSCANLINE */
389 pb
->prev_last_fr
= -999;
391 /* Reset DMA controllers */
392 planb_dbdma_stop(&pb
->planb_base
->ch2
);
393 planb_dbdma_stop(&pb
->planb_base
->ch1
);
398 static void planb_prepare_close(struct planb
*pb
)
402 /* make sure the dma's are idle */
403 planb_dbdma_stop(&pb
->planb_base
->ch2
);
404 planb_dbdma_stop(&pb
->planb_base
->ch1
);
405 /* free kernel memory of command buffers */
406 if(pb
->priv_space
!= 0) {
407 kfree (pb
->priv_space
);
409 pb
->cmd_buff_inited
= 0;
412 for (i
= 0; i
< pb
->rawbuf_size
; i
++) {
413 ClearPageReserved(virt_to_page(pb
->rawbuf
[i
]));
414 free_pages((unsigned long)pb
->rawbuf
[i
], 0);
421 /*****************************/
422 /* overlay support functions */
423 /*****************************/
425 static inline int overlay_is_active(struct planb
*pb
)
427 unsigned int size
= pb
->tab_size
* sizeof(struct dbdma_cmd
);
428 unsigned int caddr
= (unsigned)in_le32(&pb
->planb_base
->ch1
.cmdptr
);
430 return (in_le32(&pb
->overlay_last1
->cmd_dep
) == pb
->ch1_cmd_phys
)
431 && (caddr
< (pb
->ch1_cmd_phys
+ size
))
432 && (caddr
>= (unsigned)pb
->ch1_cmd_phys
);
435 static void overlay_start(struct planb
*pb
)
438 DEBUG("PlanB: overlay_start()\n");
440 if(ACTIVE
& in_le32(&pb
->planb_base
->ch1
.status
)) {
442 DEBUG("PlanB: presumably, grabbing is in progress...\n");
444 planb_dbdma_stop(&pb
->planb_base
->ch2
);
445 out_le32 (&pb
->planb_base
->ch2
.cmdptr
,
446 virt_to_bus(pb
->ch2_cmd
));
447 planb_dbdma_restart(&pb
->planb_base
->ch2
);
448 st_le16 (&pb
->ch1_cmd
->command
, DBDMA_NOP
);
449 tab_cmd_dbdma(pb
->last_cmd
[pb
->last_fr
],
450 DBDMA_NOP
| BR_ALWAYS
,
451 virt_to_bus(pb
->ch1_cmd
));
453 pb
->prev_last_fr
= pb
->last_fr
;
455 if(!(ACTIVE
& in_le32(&pb
->planb_base
->ch1
.status
))) {
456 IDEBUG("PlanB: became inactive "
457 "in the mean time... reactivating\n");
458 planb_dbdma_stop(&pb
->planb_base
->ch1
);
459 out_le32 (&pb
->planb_base
->ch1
.cmdptr
,
460 virt_to_bus(pb
->ch1_cmd
));
461 planb_dbdma_restart(&pb
->planb_base
->ch1
);
465 DEBUG("PlanB: currently idle, so can do whatever\n");
467 planb_dbdma_stop(&pb
->planb_base
->ch2
);
468 planb_dbdma_stop(&pb
->planb_base
->ch1
);
469 st_le32 (&pb
->planb_base
->ch2
.cmdptr
,
470 virt_to_bus(pb
->ch2_cmd
));
471 st_le32 (&pb
->planb_base
->ch1
.cmdptr
,
472 virt_to_bus(pb
->ch1_cmd
));
473 out_le16 (&pb
->ch1_cmd
->command
, DBDMA_NOP
);
474 planb_dbdma_restart(&pb
->planb_base
->ch2
);
475 planb_dbdma_restart(&pb
->planb_base
->ch1
);
481 static void overlay_stop(struct planb
*pb
)
483 DEBUG("PlanB: overlay_stop()\n");
485 if(pb
->last_fr
== -1) {
487 DEBUG("PlanB: no grabbing, it seems...\n");
489 planb_dbdma_stop(&pb
->planb_base
->ch2
);
490 planb_dbdma_stop(&pb
->planb_base
->ch1
);
492 } else if(pb
->last_fr
== -2) {
493 unsigned int cmd_dep
;
494 tab_cmd_dbdma(pb
->cap_cmd
[pb
->prev_last_fr
], DBDMA_STOP
, 0);
496 cmd_dep
= (unsigned int)in_le32(&pb
->overlay_last1
->cmd_dep
);
497 if(overlay_is_active(pb
)) {
499 DEBUG("PlanB: overlay is currently active\n");
501 planb_dbdma_stop(&pb
->planb_base
->ch2
);
502 planb_dbdma_stop(&pb
->planb_base
->ch1
);
503 if(cmd_dep
!= pb
->ch1_cmd_phys
) {
504 out_le32(&pb
->planb_base
->ch1
.cmdptr
,
505 virt_to_bus(pb
->overlay_last1
));
506 planb_dbdma_restart(&pb
->planb_base
->ch1
);
509 pb
->last_fr
= pb
->prev_last_fr
;
510 pb
->prev_last_fr
= -999;
515 static void suspend_overlay(struct planb
*pb
)
518 struct dbdma_cmd last
;
520 DEBUG("PlanB: suspend_overlay: %d\n", pb
->suspend
);
524 if(ACTIVE
& in_le32(&pb
->planb_base
->ch1
.status
)) {
525 if(pb
->last_fr
== -2) {
526 fr
= pb
->prev_last_fr
;
527 memcpy(&last
, (void*)pb
->last_cmd
[fr
], sizeof(last
));
528 tab_cmd_dbdma(pb
->last_cmd
[fr
], DBDMA_STOP
, 0);
530 if(overlay_is_active(pb
)) {
531 planb_dbdma_stop(&pb
->planb_base
->ch2
);
532 planb_dbdma_stop(&pb
->planb_base
->ch1
);
533 pb
->suspended
.overlay
= 1;
534 pb
->suspended
.frame
= fr
;
535 memcpy(&pb
->suspended
.cmd
, &last
, sizeof(last
));
539 pb
->suspended
.overlay
= 0;
540 pb
->suspended
.frame
= fr
;
541 memcpy(&pb
->suspended
.cmd
, &last
, sizeof(last
));
545 static void resume_overlay(struct planb
*pb
)
548 DEBUG("PlanB: resume_overlay: %d\n", pb
->suspend
);
552 if(pb
->suspended
.frame
!= -1) {
553 memcpy((void*)pb
->last_cmd
[pb
->suspended
.frame
],
554 &pb
->suspended
.cmd
, sizeof(pb
->suspended
.cmd
));
556 if(ACTIVE
& in_le32(&pb
->planb_base
->ch1
.status
)) {
559 if(pb
->suspended
.overlay
) {
561 DEBUG("PlanB: overlay being resumed\n");
563 st_le16 (&pb
->ch1_cmd
->command
, DBDMA_NOP
);
564 st_le16 (&pb
->ch2_cmd
->command
, DBDMA_NOP
);
565 /* Set command buffer addresses */
566 st_le32(&pb
->planb_base
->ch1
.cmdptr
,
567 virt_to_bus(pb
->overlay_last1
));
568 out_le32(&pb
->planb_base
->ch2
.cmdptr
,
569 virt_to_bus(pb
->overlay_last2
));
570 /* Start the DMA controller */
571 out_le32 (&pb
->planb_base
->ch2
.control
,
572 PLANB_CLR(PAUSE
) | PLANB_SET(RUN
|WAKE
));
573 out_le32 (&pb
->planb_base
->ch1
.control
,
574 PLANB_CLR(PAUSE
) | PLANB_SET(RUN
|WAKE
));
575 } else if(pb
->suspended
.frame
!= -1) {
576 out_le32(&pb
->planb_base
->ch1
.cmdptr
,
577 virt_to_bus(pb
->last_cmd
[pb
->suspended
.frame
]));
578 out_le32 (&pb
->planb_base
->ch1
.control
,
579 PLANB_CLR(PAUSE
) | PLANB_SET(RUN
|WAKE
));
584 wake_up_interruptible(&pb
->suspendq
);
587 static void add_clip(struct planb
*pb
, struct video_clip
*clip
)
589 volatile unsigned char *base
;
590 int xc
= clip
->x
, yc
= clip
->y
;
591 int wc
= clip
->width
, hc
= clip
->height
;
592 int ww
= pb
->win
.width
, hw
= pb
->win
.height
;
593 int x
, y
, xtmp1
, xtmp2
;
595 DEBUG("PlanB: clip %dx%d+%d+%d\n", wc
, hc
, xc
, yc
);
607 if(wc
<= 0) /* Nothing to do */
612 for (y
= yc
; y
< yc
+hc
; y
++) {
615 base
= pb
->mask
+ y
*96;
616 if(xc
!= 0 || wc
>= 8)
617 *(base
+ xtmp1
) &= (unsigned char)(0x00ff &
619 for (x
= xtmp1
+ 1; x
< xtmp2
; x
++) {
623 *(base
+ xtmp2
) &= (unsigned char)(0x00ff >>
630 static void fill_cmd_buff(struct planb
*pb
)
633 volatile struct dbdma_cmd last
;
635 DEBUG("PlanB: fill_cmd_buff()\n");
637 if(pb
->overlay_last1
!= pb
->ch1_cmd
) {
639 last
= *(pb
->overlay_last1
);
641 memset ((void *) pb
->ch1_cmd
, 0, 2 * pb
->tab_size
642 * sizeof(struct dbdma_cmd
));
645 *(pb
->overlay_last1
) = last
;
646 if(pb
->suspended
.overlay
) {
647 unsigned long jump_addr
= in_le32(&pb
->overlay_last1
->cmd_dep
);
648 if(jump_addr
!= pb
->ch1_cmd_phys
) {
651 DEBUG("PlanB: adjusting ch1's jump address\n");
653 for(i
= 0; i
< MAX_GBUFFERS
; i
++) {
654 if(pb
->need_pre_capture
[i
]) {
655 if(jump_addr
== virt_to_bus(pb
->pre_cmd
[i
]))
658 if(jump_addr
== virt_to_bus(pb
->cap_cmd
[i
]))
663 DEBUG("PlanB: not found...\n");
667 if(pb
->need_pre_capture
[i
])
668 out_le32(&pb
->pre_cmd
[i
]->phy_addr
,
669 virt_to_bus(pb
->overlay_last1
));
671 out_le32(&pb
->cap_cmd
[i
]->phy_addr
,
672 virt_to_bus(pb
->overlay_last1
));
676 pb
->cmd_buff_inited
= 1;
681 static void cmd_buff(struct planb
*pb
)
683 int i
, bpp
, count
, nlines
, stepsize
, interlace
;
684 unsigned long base
, jump
, addr_com
, addr_dep
;
685 volatile struct dbdma_cmd
*c1
= pb
->ch1_cmd
;
686 volatile struct dbdma_cmd
*c2
= pb
->ch2_cmd
;
688 interlace
= pb
->win
.interlace
;
690 count
= (bpp
* ((pb
->win
.x
+ pb
->win
.width
> pb
->win
.swidth
) ?
691 (pb
->win
.swidth
- pb
->win
.x
) : pb
->win
.width
));
692 nlines
= ((pb
->win
.y
+ pb
->win
.height
> pb
->win
.sheight
) ?
693 (pb
->win
.sheight
- pb
->win
.y
) : pb
->win
.height
);
697 /* Preamble commands: */
698 addr_com
= virt_to_bus(c1
);
699 addr_dep
= virt_to_bus(&c1
->cmd_dep
);
700 tab_cmd_dbdma(c1
++, DBDMA_NOP
, 0);
701 jump
= virt_to_bus(c1
+16); /* 14 by cmd_geo_setup() and 2 for padding */
702 if((c1
= cmd_geo_setup(c1
, pb
->win
.width
, pb
->win
.height
, interlace
,
703 bpp
, 1, pb
)) == NULL
) {
704 printk(KERN_WARNING
"PlanB: encountered serious problems\n");
705 tab_cmd_dbdma(pb
->ch1_cmd
+ 1, DBDMA_STOP
, 0);
706 tab_cmd_dbdma(pb
->ch2_cmd
+ 1, DBDMA_STOP
, 0);
709 tab_cmd_store(c1
++, addr_com
, (unsigned)(DBDMA_NOP
| BR_ALWAYS
) << 16);
710 tab_cmd_store(c1
++, addr_dep
, jump
);
711 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->ch1
.wait_sel
),
712 PLANB_SET(FIELD_SYNC
));
713 /* (1) wait for field sync to be set */
714 tab_cmd_dbdma(c1
++, DBDMA_NOP
| WAIT_IFCLR
, 0);
715 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->ch1
.br_sel
),
716 PLANB_SET(ODD_FIELD
));
717 /* wait for field sync to be cleared */
718 tab_cmd_dbdma(c1
++, DBDMA_NOP
| WAIT_IFSET
, 0);
719 /* if not odd field, wait until field sync is set again */
720 tab_cmd_dbdma(c1
, DBDMA_NOP
| BR_IFSET
, virt_to_bus(c1
-3)); c1
++;
721 /* assert ch_sync to ch2 */
722 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->ch2
.control
),
724 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->ch1
.br_sel
),
725 PLANB_SET(DMA_ABORT
));
727 base
= (pb
->frame_buffer_phys
+ pb
->offset
+ pb
->win
.y
* (pb
->win
.bpl
728 + pb
->win
.pad
) + pb
->win
.x
* bpp
);
732 jump
= virt_to_bus(c1
+ (nlines
+ 1) / 2);
735 jump
= virt_to_bus(c1
+ nlines
);
738 /* even field data: */
739 for (i
=0; i
< nlines
; i
+= stepsize
, c1
++)
740 tab_cmd_gen(c1
, INPUT_MORE
| KEY_STREAM0
| BR_IFSET
,
741 count
, base
+ i
* (pb
->win
.bpl
+ pb
->win
.pad
), jump
);
743 /* For non-interlaced, we use even fields only */
745 goto cmd_tab_data_end
;
747 /* Resync to odd field */
748 /* (2) wait for field sync to be set */
749 tab_cmd_dbdma(c1
++, DBDMA_NOP
| WAIT_IFCLR
, 0);
750 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->ch1
.br_sel
),
751 PLANB_SET(ODD_FIELD
));
752 /* wait for field sync to be cleared */
753 tab_cmd_dbdma(c1
++, DBDMA_NOP
| WAIT_IFSET
, 0);
754 /* if not odd field, wait until field sync is set again */
755 tab_cmd_dbdma(c1
, DBDMA_NOP
| BR_IFCLR
, virt_to_bus(c1
-3)); c1
++;
756 /* assert ch_sync to ch2 */
757 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->ch2
.control
),
759 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->ch1
.br_sel
),
760 PLANB_SET(DMA_ABORT
));
762 /* odd field data: */
763 jump
= virt_to_bus(c1
+ nlines
/ 2);
764 for (i
=1; i
< nlines
; i
+= stepsize
, c1
++)
765 tab_cmd_gen(c1
, INPUT_MORE
| KEY_STREAM0
| BR_IFSET
, count
,
766 base
+ i
* (pb
->win
.bpl
+ pb
->win
.pad
), jump
);
768 /* And jump back to the start */
770 pb
->overlay_last1
= c1
; /* keep a pointer to the last command */
771 tab_cmd_dbdma(c1
, DBDMA_NOP
| BR_ALWAYS
, virt_to_bus(pb
->ch1_cmd
));
773 /* Clipmask command buffer */
775 /* Preamble commands: */
776 tab_cmd_dbdma(c2
++, DBDMA_NOP
, 0);
777 tab_cmd_store(c2
++, (unsigned)(&pb
->planb_base_phys
->ch2
.wait_sel
),
779 /* wait until ch1 asserts ch_sync */
780 tab_cmd_dbdma(c2
++, DBDMA_NOP
| WAIT_IFCLR
, 0);
781 /* clear ch_sync asserted by ch1 */
782 tab_cmd_store(c2
++, (unsigned)(&pb
->planb_base_phys
->ch2
.control
),
784 tab_cmd_store(c2
++, (unsigned)(&pb
->planb_base_phys
->ch2
.wait_sel
),
785 PLANB_SET(FIELD_SYNC
));
786 tab_cmd_store(c2
++, (unsigned)(&pb
->planb_base_phys
->ch2
.br_sel
),
787 PLANB_SET(ODD_FIELD
));
789 /* jump to end of even field if appropriate */
790 /* this points to (interlace)? pos. C: pos. B */
791 jump
= (interlace
) ? virt_to_bus(c2
+ (nlines
+ 1) / 2 + 2):
792 virt_to_bus(c2
+ nlines
+ 2);
793 /* if odd field, skip over to odd field clipmasking */
794 tab_cmd_dbdma(c2
++, DBDMA_NOP
| BR_IFSET
, jump
);
796 /* even field mask: */
797 tab_cmd_store(c2
++, (unsigned)(&pb
->planb_base_phys
->ch2
.br_sel
),
798 PLANB_SET(DMA_ABORT
));
799 /* this points to pos. B */
800 jump
= (interlace
) ? virt_to_bus(c2
+ nlines
+ 1):
801 virt_to_bus(c2
+ nlines
);
802 base
= virt_to_bus(pb
->mask
);
803 for (i
=0; i
< nlines
; i
+= stepsize
, c2
++)
804 tab_cmd_gen(c2
, OUTPUT_MORE
| KEY_STREAM0
| BR_IFSET
, 96,
805 base
+ i
* 96, jump
);
807 /* For non-interlaced, we use only even fields */
809 goto cmd_tab_mask_end
;
811 /* odd field mask: */
812 /* C */ tab_cmd_store(c2
++, (unsigned)(&pb
->planb_base_phys
->ch2
.br_sel
),
813 PLANB_SET(DMA_ABORT
));
814 /* this points to pos. B */
815 jump
= virt_to_bus(c2
+ nlines
/ 2);
816 base
= virt_to_bus(pb
->mask
);
817 for (i
=1; i
< nlines
; i
+= 2, c2
++) /* abort if set */
818 tab_cmd_gen(c2
, OUTPUT_MORE
| KEY_STREAM0
| BR_IFSET
, 96,
819 base
+ i
* 96, jump
);
821 /* Inform channel 1 and jump back to start */
823 /* ok, I just realized this is kind of flawed. */
824 /* this part is reached only after odd field clipmasking. */
825 /* wanna clean up? */
826 /* wait for field sync to be set */
827 /* corresponds to fsync (1) of ch1 */
828 /* B */ tab_cmd_dbdma(c2
++, DBDMA_NOP
| WAIT_IFCLR
, 0);
829 /* restart ch1, meant to clear any dead bit or something */
830 tab_cmd_store(c2
++, (unsigned)(&pb
->planb_base_phys
->ch1
.control
),
832 tab_cmd_store(c2
++, (unsigned)(&pb
->planb_base_phys
->ch1
.control
),
834 pb
->overlay_last2
= c2
; /* keep a pointer to the last command */
835 /* start over even field clipmasking */
836 tab_cmd_dbdma(c2
, DBDMA_NOP
| BR_ALWAYS
, virt_to_bus(pb
->ch2_cmd
));
842 /*********************************/
843 /* grabdisplay support functions */
844 /*********************************/
846 static int palette2fmt
[] = {
864 #define PLANB_PALETTE_MAX 15
866 static int vgrab(struct planb
*pb
, struct video_mmap
*mp
)
868 unsigned int fr
= mp
->frame
;
871 if(pb
->rawbuf
==NULL
) {
873 if((err
=grabbuf_alloc(pb
)))
877 IDEBUG("PlanB: grab %d: %dx%d(%u)\n", pb
->grabbing
,
878 mp
->width
, mp
->height
, fr
);
880 if(pb
->grabbing
>= MAX_GBUFFERS
)
882 if(fr
> (MAX_GBUFFERS
- 1) || fr
< 0)
884 if(mp
->height
<= 0 || mp
->width
<= 0)
886 if(mp
->format
< 0 || mp
->format
>= PLANB_PALETTE_MAX
)
888 if((format
= palette2fmt
[mp
->format
]) == 0)
890 if (mp
->height
* mp
->width
* format
> PLANB_MAX_FBUF
) /* format = bpp */
894 if(mp
->width
!= pb
->gwidth
[fr
] || mp
->height
!= pb
->gheight
[fr
] ||
895 format
!= pb
->gfmt
[fr
] || (pb
->gnorm_switch
[fr
])) {
897 #ifndef PLANB_GSCANLINE
898 unsigned int osize
= pb
->gwidth
[fr
] * pb
->gheight
[fr
]
900 unsigned int nsize
= mp
->width
* mp
->height
* format
;
903 IDEBUG("PlanB: gwidth = %d, gheight = %d, mp->format = %u\n",
904 mp
->width
, mp
->height
, mp
->format
);
906 #ifndef PLANB_GSCANLINE
907 if(pb
->gnorm_switch
[fr
])
910 for(i
= pb
->gbuf_idx
[fr
]; osize
> 0; i
++) {
911 memset((void *)pb
->rawbuf
[i
], 0, PAGE_SIZE
);
915 for(i
= pb
->l_fr_addr_idx
[fr
]; i
< pb
->l_fr_addr_idx
[fr
]
917 memset((void *)pb
->rawbuf
[i
], 0, PAGE_SIZE
);
921 if(pb->gnorm_switch[fr])
922 memset((void *)pb->gbuffer[fr], 0,
923 pb->gbytes_per_line * pb->gheight[fr]);
926 for(i = 0; i < pb->gheight[fr]; i++) {
927 memset((void *)(pb->gbuffer[fr]
928 + pb->gbytes_per_line * i
933 pb
->gwidth
[fr
] = mp
->width
;
934 pb
->gheight
[fr
] = mp
->height
;
935 pb
->gfmt
[fr
] = format
;
936 pb
->last_cmd
[fr
] = setup_grab_cmd(fr
, pb
);
937 planb_pre_capture(fr
, pb
->gfmt
[fr
], pb
); /* gfmt = bpp */
938 pb
->need_pre_capture
[fr
] = 1;
939 pb
->gnorm_switch
[fr
] = 0;
941 pb
->need_pre_capture
[fr
] = 0;
942 pb
->frame_stat
[fr
] = GBUFFER_GRABBING
;
943 if(!(ACTIVE
& in_le32(&pb
->planb_base
->ch1
.status
))) {
945 IDEBUG("PlanB: ch1 inactive, initiating grabbing\n");
947 planb_dbdma_stop(&pb
->planb_base
->ch1
);
948 if(pb
->need_pre_capture
[fr
]) {
950 IDEBUG("PlanB: padding pre-capture sequence\n");
952 out_le32 (&pb
->planb_base
->ch1
.cmdptr
,
953 virt_to_bus(pb
->pre_cmd
[fr
]));
955 tab_cmd_dbdma(pb
->last_cmd
[fr
], DBDMA_STOP
, 0);
956 tab_cmd_dbdma(pb
->cap_cmd
[fr
], DBDMA_NOP
, 0);
957 /* let's be on the safe side. here is not timing critical. */
958 tab_cmd_dbdma((pb
->cap_cmd
[fr
] + 1), DBDMA_NOP
, 0);
959 out_le32 (&pb
->planb_base
->ch1
.cmdptr
,
960 virt_to_bus(pb
->cap_cmd
[fr
]));
962 planb_dbdma_restart(&pb
->planb_base
->ch1
);
967 IDEBUG("PlanB: ch1 active, grabbing being queued\n");
969 if((pb
->last_fr
== -1) || ((pb
->last_fr
== -2) &&
970 overlay_is_active(pb
))) {
972 IDEBUG("PlanB: overlay is active, grabbing defered\n");
974 tab_cmd_dbdma(pb
->last_cmd
[fr
],
975 DBDMA_NOP
| BR_ALWAYS
,
976 virt_to_bus(pb
->ch1_cmd
));
977 if(pb
->need_pre_capture
[fr
]) {
979 IDEBUG("PlanB: padding pre-capture sequence\n");
981 tab_cmd_store(pb
->pre_cmd
[fr
],
982 virt_to_bus(&pb
->overlay_last1
->cmd_dep
),
983 virt_to_bus(pb
->ch1_cmd
));
985 out_le32 (&pb
->overlay_last1
->cmd_dep
,
986 virt_to_bus(pb
->pre_cmd
[fr
]));
988 tab_cmd_store(pb
->cap_cmd
[fr
],
989 virt_to_bus(&pb
->overlay_last1
->cmd_dep
),
990 virt_to_bus(pb
->ch1_cmd
));
991 tab_cmd_dbdma((pb
->cap_cmd
[fr
] + 1),
994 out_le32 (&pb
->overlay_last1
->cmd_dep
,
995 virt_to_bus(pb
->cap_cmd
[fr
]));
997 for(i
= 0; overlay_is_active(pb
) && i
< 999; i
++)
998 IDEBUG("PlanB: waiting for overlay done\n");
999 tab_cmd_dbdma(pb
->ch1_cmd
, DBDMA_NOP
, 0);
1000 pb
->prev_last_fr
= fr
;
1002 } else if(pb
->last_fr
== -2) {
1004 IDEBUG("PlanB: mixed mode detected, grabbing"
1005 " will be done before activating overlay\n");
1007 tab_cmd_dbdma(pb
->ch1_cmd
, DBDMA_NOP
, 0);
1008 if(pb
->need_pre_capture
[fr
]) {
1010 IDEBUG("PlanB: padding pre-capture sequence\n");
1012 tab_cmd_dbdma(pb
->last_cmd
[pb
->prev_last_fr
],
1013 DBDMA_NOP
| BR_ALWAYS
,
1014 virt_to_bus(pb
->pre_cmd
[fr
]));
1017 tab_cmd_dbdma(pb
->cap_cmd
[fr
], DBDMA_NOP
, 0);
1018 if(pb
->gwidth
[pb
->prev_last_fr
] !=
1020 || pb
->gheight
[pb
->prev_last_fr
] !=
1022 || pb
->gfmt
[pb
->prev_last_fr
] !=
1024 tab_cmd_dbdma((pb
->cap_cmd
[fr
] + 1),
1027 tab_cmd_dbdma((pb
->cap_cmd
[fr
] + 1),
1028 DBDMA_NOP
| BR_ALWAYS
,
1029 virt_to_bus(pb
->cap_cmd
[fr
] + 16));
1030 tab_cmd_dbdma(pb
->last_cmd
[pb
->prev_last_fr
],
1031 DBDMA_NOP
| BR_ALWAYS
,
1032 virt_to_bus(pb
->cap_cmd
[fr
]));
1035 tab_cmd_dbdma(pb
->last_cmd
[fr
],
1036 DBDMA_NOP
| BR_ALWAYS
,
1037 virt_to_bus(pb
->ch1_cmd
));
1039 pb
->prev_last_fr
= fr
;
1043 IDEBUG("PlanB: active grabbing session detected\n");
1045 if(pb
->need_pre_capture
[fr
]) {
1047 IDEBUG("PlanB: padding pre-capture sequence\n");
1049 tab_cmd_dbdma(pb
->last_cmd
[pb
->last_fr
],
1050 DBDMA_NOP
| BR_ALWAYS
,
1051 virt_to_bus(pb
->pre_cmd
[fr
]));
1054 tab_cmd_dbdma(pb
->last_cmd
[fr
], DBDMA_STOP
, 0);
1055 tab_cmd_dbdma(pb
->cap_cmd
[fr
], DBDMA_NOP
, 0);
1056 if(pb
->gwidth
[pb
->last_fr
] != pb
->gwidth
[fr
]
1057 || pb
->gheight
[pb
->last_fr
] !=
1059 || pb
->gfmt
[pb
->last_fr
] !=
1061 tab_cmd_dbdma((pb
->cap_cmd
[fr
] + 1),
1064 tab_cmd_dbdma((pb
->cap_cmd
[fr
] + 1),
1065 DBDMA_NOP
| BR_ALWAYS
,
1066 virt_to_bus(pb
->cap_cmd
[fr
] + 16));
1067 tab_cmd_dbdma(pb
->last_cmd
[pb
->last_fr
],
1068 DBDMA_NOP
| BR_ALWAYS
,
1069 virt_to_bus(pb
->cap_cmd
[fr
]));
1074 if(!(ACTIVE
& in_le32(&pb
->planb_base
->ch1
.status
))) {
1076 IDEBUG("PlanB: became inactive in the mean time..."
1079 planb_dbdma_stop(&pb
->planb_base
->ch1
);
1080 out_le32 (&pb
->planb_base
->ch1
.cmdptr
,
1081 virt_to_bus(pb
->cap_cmd
[fr
]));
1082 planb_dbdma_restart(&pb
->planb_base
->ch1
);
1091 static void planb_pre_capture(int fr
, int bpp
, struct planb
*pb
)
1093 volatile struct dbdma_cmd
*c1
= pb
->pre_cmd
[fr
];
1094 int interlace
= (pb
->gheight
[fr
] > pb
->maxlines
/2)? 1: 0;
1096 tab_cmd_dbdma(c1
++, DBDMA_NOP
, 0);
1097 if((c1
= cmd_geo_setup(c1
, pb
->gwidth
[fr
], pb
->gheight
[fr
], interlace
,
1098 bpp
, 0, pb
)) == NULL
) {
1099 printk(KERN_WARNING
"PlanB: encountered some problems\n");
1100 tab_cmd_dbdma(pb
->pre_cmd
[fr
] + 1, DBDMA_STOP
, 0);
1103 /* Sync to even field */
1104 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->ch1
.wait_sel
),
1105 PLANB_SET(FIELD_SYNC
));
1106 tab_cmd_dbdma(c1
++, DBDMA_NOP
| WAIT_IFCLR
, 0);
1107 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->ch1
.br_sel
),
1108 PLANB_SET(ODD_FIELD
));
1109 tab_cmd_dbdma(c1
++, DBDMA_NOP
| WAIT_IFSET
, 0);
1110 tab_cmd_dbdma(c1
, DBDMA_NOP
| BR_IFSET
, virt_to_bus(c1
-3)); c1
++;
1111 tab_cmd_dbdma(c1
++, DBDMA_NOP
| INTR_ALWAYS
, 0);
1112 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->ch1
.br_sel
),
1113 PLANB_SET(DMA_ABORT
));
1114 /* For non-interlaced, we use even fields only */
1115 if (pb
->gheight
[fr
] <= pb
->maxlines
/2)
1116 goto cmd_tab_data_end
;
1117 /* Sync to odd field */
1118 tab_cmd_dbdma(c1
++, DBDMA_NOP
| WAIT_IFCLR
, 0);
1119 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->ch1
.br_sel
),
1120 PLANB_SET(ODD_FIELD
));
1121 tab_cmd_dbdma(c1
++, DBDMA_NOP
| WAIT_IFSET
, 0);
1122 tab_cmd_dbdma(c1
, DBDMA_NOP
| BR_IFCLR
, virt_to_bus(c1
-3)); c1
++;
1123 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->ch1
.br_sel
),
1124 PLANB_SET(DMA_ABORT
));
1126 tab_cmd_dbdma(c1
, DBDMA_NOP
| BR_ALWAYS
, virt_to_bus(pb
->cap_cmd
[fr
]));
1131 static volatile struct dbdma_cmd
*setup_grab_cmd(int fr
, struct planb
*pb
)
1133 int i
, bpp
, count
, nlines
, stepsize
, interlace
;
1134 #ifdef PLANB_GSCANLINE
1137 int nlpp
, leftover1
;
1142 volatile struct dbdma_cmd
*c1
;
1143 volatile struct dbdma_cmd
*jump_addr
;
1145 c1
= pb
->cap_cmd
[fr
];
1146 interlace
= (pb
->gheight
[fr
] > pb
->maxlines
/2)? 1: 0;
1147 bpp
= pb
->gfmt
[fr
]; /* gfmt = bpp */
1148 count
= bpp
* pb
->gwidth
[fr
];
1149 nlines
= pb
->gheight
[fr
];
1150 #ifdef PLANB_GSCANLINE
1151 scanline
= pb
->gbytes_per_line
;
1153 pb
->lsize
[fr
] = count
;
1159 /* Preamble commands: */
1160 tab_cmd_dbdma(c1
++, DBDMA_NOP
, 0);
1161 tab_cmd_dbdma(c1
, DBDMA_NOP
| BR_ALWAYS
, virt_to_bus(c1
+ 16)); c1
++;
1162 if((c1
= cmd_geo_setup(c1
, pb
->gwidth
[fr
], pb
->gheight
[fr
], interlace
,
1163 bpp
, 0, pb
)) == NULL
) {
1164 printk(KERN_WARNING
"PlanB: encountered serious problems\n");
1165 tab_cmd_dbdma(pb
->cap_cmd
[fr
] + 1, DBDMA_STOP
, 0);
1166 return (pb
->cap_cmd
[fr
] + 2);
1168 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->ch1
.wait_sel
),
1169 PLANB_SET(FIELD_SYNC
));
1170 tab_cmd_dbdma(c1
++, DBDMA_NOP
| WAIT_IFCLR
, 0);
1171 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->ch1
.br_sel
),
1172 PLANB_SET(ODD_FIELD
));
1173 tab_cmd_dbdma(c1
++, DBDMA_NOP
| WAIT_IFSET
, 0);
1174 tab_cmd_dbdma(c1
, DBDMA_NOP
| BR_IFSET
, virt_to_bus(c1
-3)); c1
++;
1175 tab_cmd_dbdma(c1
++, DBDMA_NOP
| INTR_ALWAYS
, 0);
1176 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->ch1
.br_sel
),
1177 PLANB_SET(DMA_ABORT
));
1181 jump_addr
= c1
+ TAB_FACTOR
* (nlines
+ 1) / 2;
1184 jump_addr
= c1
+ TAB_FACTOR
* nlines
;
1186 jump
= virt_to_bus(jump_addr
);
1188 /* even field data: */
1190 pagei
= pb
->gbuf_idx
[fr
];
1191 #ifdef PLANB_GSCANLINE
1192 for (i
= 0; i
< nlines
; i
+= stepsize
) {
1193 tab_cmd_gen(c1
++, INPUT_MORE
| BR_IFSET
, count
,
1194 virt_to_bus(pb
->rawbuf
[pagei
1195 + i
* scanline
/ PAGE_SIZE
]), jump
);
1203 base
= virt_to_bus(pb
->rawbuf
[pagei
]);
1204 nlpp
= (PAGE_SIZE
- leftover1
) / count
/ stepsize
;
1205 for(j
= 0; j
< nlpp
&& i
< nlines
; j
++, i
+= stepsize
, c1
++)
1206 tab_cmd_gen(c1
, INPUT_MORE
| KEY_STREAM0
| BR_IFSET
,
1207 count
, base
+ count
* j
* stepsize
+ leftover1
, jump
);
1209 int lov0
= PAGE_SIZE
- count
* nlpp
* stepsize
- leftover1
;
1215 tab_cmd_gen(c1
++, INPUT_MORE
| BR_IFSET
, count
, base
1216 + count
* nlpp
* stepsize
+ leftover1
, jump
);
1218 pb
->l_to_addr
[fr
][pb
->lnum
[fr
]] = pb
->rawbuf
[pagei
]
1219 + count
* nlpp
* stepsize
+ leftover1
;
1220 pb
->l_to_next_idx
[fr
][pb
->lnum
[fr
]] = pagei
+ 1;
1221 pb
->l_to_next_size
[fr
][pb
->lnum
[fr
]] = count
- lov0
;
1222 tab_cmd_gen(c1
++, INPUT_MORE
| BR_IFSET
, count
,
1223 virt_to_bus(pb
->rawbuf
[pb
->l_fr_addr_idx
[fr
]
1224 + pb
->lnum
[fr
]]), jump
);
1225 if(++pb
->lnum
[fr
] > MAX_LNUM
)
1228 leftover1
= count
* stepsize
- lov0
;
1233 } while(i
< nlines
);
1234 tab_cmd_dbdma(c1
, DBDMA_NOP
| BR_ALWAYS
, jump
);
1236 #endif /* PLANB_GSCANLINE */
1238 /* For non-interlaced, we use even fields only */
1240 goto cmd_tab_data_end
;
1242 /* Sync to odd field */
1243 tab_cmd_dbdma(c1
++, DBDMA_NOP
| WAIT_IFCLR
, 0);
1244 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->ch1
.br_sel
),
1245 PLANB_SET(ODD_FIELD
));
1246 tab_cmd_dbdma(c1
++, DBDMA_NOP
| WAIT_IFSET
, 0);
1247 tab_cmd_dbdma(c1
, DBDMA_NOP
| BR_IFCLR
, virt_to_bus(c1
-3)); c1
++;
1248 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->ch1
.br_sel
),
1249 PLANB_SET(DMA_ABORT
));
1251 /* odd field data: */
1252 jump_addr
= c1
+ TAB_FACTOR
* nlines
/ 2;
1253 jump
= virt_to_bus(jump_addr
);
1254 #ifdef PLANB_GSCANLINE
1255 for (i
= 1; i
< nlines
; i
+= stepsize
) {
1256 tab_cmd_gen(c1
++, INPUT_MORE
| BR_IFSET
, count
,
1257 virt_to_bus(pb
->rawbuf
[pagei
1258 + i
* scanline
/ PAGE_SIZE
]), jump
);
1263 pagei
= pb
->gbuf_idx
[fr
];
1269 base
= virt_to_bus(pb
->rawbuf
[pagei
]);
1270 nlpp
= (PAGE_SIZE
- leftover1
) / count
/ stepsize
;
1271 if(leftover1
>= count
) {
1272 tab_cmd_gen(c1
++, INPUT_MORE
| KEY_STREAM0
| BR_IFSET
, count
,
1273 base
+ leftover1
- count
, jump
);
1276 for(j
= 0; j
< nlpp
&& i
< nlines
; j
++, i
+= stepsize
, c1
++)
1277 tab_cmd_gen(c1
, INPUT_MORE
| KEY_STREAM0
| BR_IFSET
, count
,
1278 base
+ count
* (j
* stepsize
+ 1) + leftover1
, jump
);
1280 int lov0
= PAGE_SIZE
- count
* nlpp
* stepsize
- leftover1
;
1286 pb
->l_to_addr
[fr
][pb
->lnum
[fr
]] = pb
->rawbuf
[pagei
]
1287 + count
* (nlpp
* stepsize
+ 1) + leftover1
;
1288 pb
->l_to_next_idx
[fr
][pb
->lnum
[fr
]] = pagei
+ 1;
1289 pb
->l_to_next_size
[fr
][pb
->lnum
[fr
]] = count
* stepsize
1291 tab_cmd_gen(c1
++, INPUT_MORE
| BR_IFSET
, count
,
1292 virt_to_bus(pb
->rawbuf
[pb
->l_fr_addr_idx
[fr
]
1293 + pb
->lnum
[fr
]]), jump
);
1294 if(++pb
->lnum
[fr
] > MAX_LNUM
)
1298 leftover1
= count
* stepsize
- lov0
;
1302 } while(i
< nlines
);
1304 tab_cmd_dbdma(c1
, DBDMA_NOP
| BR_ALWAYS
, jump
);
1306 #endif /* PLANB_GSCANLINE */
1309 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->intr_stat
),
1310 (fr
<< 9) | PLANB_FRM_IRQ
| PLANB_GEN_IRQ
);
1312 tab_cmd_dbdma(c1
, DBDMA_STOP
, 0);
1318 static void planb_irq(int irq
, void *dev_id
, struct pt_regs
* regs
)
1320 unsigned int stat
, astat
;
1321 struct planb
*pb
= (struct planb
*)dev_id
;
1323 IDEBUG("PlanB: planb_irq()\n");
1325 /* get/clear interrupt status bits */
1327 stat
= in_le32(&pb
->planb_base
->intr_stat
);
1328 astat
= stat
& pb
->intr_mask
;
1329 out_le32(&pb
->planb_base
->intr_stat
, PLANB_FRM_IRQ
1330 & ~astat
& stat
& ~PLANB_GEN_IRQ
);
1331 IDEBUG("PlanB: stat = %X, astat = %X\n", stat
, astat
);
1333 if(astat
& PLANB_FRM_IRQ
) {
1334 unsigned int fr
= stat
>> 9;
1335 #ifndef PLANB_GSCANLINE
1338 IDEBUG("PlanB: PLANB_FRM_IRQ\n");
1342 IDEBUG("PlanB: grab %d: fr = %d, gcount = %d\n",
1343 pb
->grabbing
, fr
, pb
->gcount
);
1344 #ifndef PLANB_GSCANLINE
1345 IDEBUG("PlanB: %d * %d bytes are being copied over\n",
1346 pb
->lnum
[fr
], pb
->lsize
[fr
]);
1347 for(i
= 0; i
< pb
->lnum
[fr
]; i
++) {
1348 int first
= pb
->lsize
[fr
] - pb
->l_to_next_size
[fr
][i
];
1350 memcpy(pb
->l_to_addr
[fr
][i
],
1351 pb
->rawbuf
[pb
->l_fr_addr_idx
[fr
] + i
],
1353 memcpy(pb
->rawbuf
[pb
->l_to_next_idx
[fr
][i
]],
1354 pb
->rawbuf
[pb
->l_fr_addr_idx
[fr
] + i
] + first
,
1355 pb
->l_to_next_size
[fr
][i
]);
1358 pb
->frame_stat
[fr
] = GBUFFER_DONE
;
1360 wake_up_interruptible(&pb
->capq
);
1363 /* incorrect interrupts? */
1364 pb
->intr_mask
= PLANB_CLR_IRQ
;
1365 out_le32(&pb
->planb_base
->intr_stat
, PLANB_CLR_IRQ
);
1366 printk(KERN_ERR
"PlanB: IRQ lockup, cleared intrrupts"
1367 " unconditionally\n");
1370 /*******************************
1371 * Device Operations functions *
1372 *******************************/
1374 static int planb_open(struct video_device
*dev
, int mode
)
1376 struct planb
*pb
= (struct planb
*)dev
;
1378 if (pb
->user
== 0) {
1380 if((err
= planb_prepare_open(pb
)) != 0)
1385 DEBUG("PlanB: device opened\n");
1389 static void planb_close(struct video_device
*dev
)
1391 struct planb
*pb
= (struct planb
*)dev
;
1393 if(pb
->user
< 1) /* ??? */
1396 if (pb
->user
== 1) {
1398 planb_dbdma_stop(&pb
->planb_base
->ch2
);
1399 planb_dbdma_stop(&pb
->planb_base
->ch1
);
1402 planb_prepare_close(pb
);
1407 DEBUG("PlanB: device closed\n");
1410 static long planb_read(struct video_device
*v
, char *buf
, unsigned long count
,
1413 DEBUG("planb: read request\n");
1417 static long planb_write(struct video_device
*v
, const char *buf
,
1418 unsigned long count
, int nonblock
)
1420 DEBUG("planb: write request\n");
1424 static int planb_ioctl(struct video_device
*dev
, unsigned int cmd
, void *arg
)
1426 struct planb
*pb
=(struct planb
*)dev
;
1432 struct video_capability b
;
1434 DEBUG("PlanB: IOCTL VIDIOCGCAP\n");
1436 strcpy (b
.name
, pb
->video_dev
.name
);
1437 b
.type
= VID_TYPE_OVERLAY
| VID_TYPE_CLIPPING
|
1438 VID_TYPE_FRAMERAM
| VID_TYPE_SCALES
|
1440 b
.channels
= 2; /* composite & svhs */
1442 b
.maxwidth
= PLANB_MAXPIXELS
;
1443 b
.maxheight
= PLANB_MAXLINES
;
1444 b
.minwidth
= 32; /* wild guess */
1446 if (copy_to_user(arg
,&b
,sizeof(b
)))
1452 struct video_buffer v
;
1456 DEBUG("PlanB: IOCTL VIDIOCSFBUF\n");
1458 if (!capable(CAP_SYS_ADMIN
)
1459 || !capable(CAP_SYS_RAWIO
))
1461 if (copy_from_user(&v
, arg
,sizeof(v
)))
1472 fmt
= PLANB_COLOUR15
;
1477 fmt
= PLANB_COLOUR32
;
1483 if (bpp
* v
.width
> v
.bytesperline
) {
1488 pb
->win
.color_fmt
= fmt
;
1489 pb
->frame_buffer_phys
= (unsigned long) v
.base
;
1490 pb
->win
.sheight
= v
.height
;
1491 pb
->win
.swidth
= v
.width
;
1492 pb
->picture
.depth
= pb
->win
.depth
= v
.depth
;
1493 pb
->win
.bpl
= pb
->win
.bpp
* pb
->win
.swidth
;
1494 pb
->win
.pad
= v
.bytesperline
- pb
->win
.bpl
;
1496 DEBUG("PlanB: Display at %p is %d by %d, bytedepth %d,"
1497 " bpl %d (+ %d)\n", v
.base
, v
.width
,v
.height
,
1498 pb
->win
.bpp
, pb
->win
.bpl
, pb
->win
.pad
);
1500 pb
->cmd_buff_inited
= 0;
1502 suspend_overlay(pb
);
1511 struct video_buffer v
;
1513 DEBUG("PlanB: IOCTL VIDIOCGFBUF\n");
1515 v
.base
= (void *)pb
->frame_buffer_phys
;
1516 v
.height
= pb
->win
.sheight
;
1517 v
.width
= pb
->win
.swidth
;
1518 v
.depth
= pb
->win
.depth
;
1519 v
.bytesperline
= pb
->win
.bpl
+ pb
->win
.pad
;
1520 if (copy_to_user(arg
, &v
, sizeof(v
)))
1528 if(copy_from_user(&i
, arg
, sizeof(i
)))
1531 DEBUG("PlanB: IOCTL VIDIOCCAPTURE Stop\n");
1540 DEBUG("PlanB: IOCTL VIDIOCCAPTURE Start\n");
1542 if (pb
->frame_buffer_phys
== 0 ||
1543 pb
->win
.width
== 0 ||
1544 pb
->win
.height
== 0)
1550 if(!(pb
->cmd_buff_inited
))
1559 struct video_channel v
;
1561 DEBUG("PlanB: IOCTL VIDIOCGCHAN\n");
1563 if(copy_from_user(&v
, arg
,sizeof(v
)))
1567 v
.type
= VIDEO_TYPE_CAMERA
;
1568 v
.norm
= pb
->win
.norm
;
1572 strcpy(v
.name
,"Composite");
1575 strcpy(v
.name
,"SVHS");
1581 if(copy_to_user(arg
,&v
,sizeof(v
)))
1588 struct video_channel v
;
1590 DEBUG("PlanB: IOCTL VIDIOCSCHAN\n");
1592 if(copy_from_user(&v
, arg
, sizeof(v
)))
1595 if (v
.norm
!= pb
->win
.norm
) {
1600 case VIDEO_MODE_PAL
:
1601 case VIDEO_MODE_SECAM
:
1602 maxlines
= PLANB_MAXLINES
;
1604 case VIDEO_MODE_NTSC
:
1605 maxlines
= PLANB_NTSC_MAXLINES
;
1612 /* empty the grabbing queue */
1613 wait_event(pb
->capq
, !pb
->grabbing
);
1614 pb
->maxlines
= maxlines
;
1615 pb
->win
.norm
= v
.norm
;
1616 /* Stop overlay if running */
1617 suspend_overlay(pb
);
1618 for(i
= 0; i
< MAX_GBUFFERS
; i
++)
1619 pb
->gnorm_switch
[i
] = 1;
1620 /* I know it's an overkill, but.... */
1622 /* ok, now init it accordingly */
1624 /* restart overlay if it was running */
1631 case 0: /* Composite */
1632 saa_set (SAA7196_IOCC
,
1633 ((saa_regs
[pb
->win
.norm
][SAA7196_IOCC
] &
1637 saa_set (SAA7196_IOCC
,
1638 ((saa_regs
[pb
->win
.norm
][SAA7196_IOCC
] &
1650 struct video_picture vp
= pb
->picture
;
1652 DEBUG("PlanB: IOCTL VIDIOCGPICT\n");
1654 switch(pb
->win
.color_fmt
) {
1656 vp
.palette
= VIDEO_PALETTE_GREY
;
1657 case PLANB_COLOUR15
:
1658 vp
.palette
= VIDEO_PALETTE_RGB555
;
1660 case PLANB_COLOUR32
:
1661 vp
.palette
= VIDEO_PALETTE_RGB32
;
1668 if(copy_to_user(arg
,&vp
,sizeof(vp
)))
1674 struct video_picture vp
;
1676 DEBUG("PlanB: IOCTL VIDIOCSPICT\n");
1678 if(copy_from_user(&vp
,arg
,sizeof(vp
)))
1681 /* Should we do sanity checks here? */
1682 saa_set (SAA7196_BRIG
, (unsigned char)
1683 ((pb
->picture
.brightness
) >> 8), pb
);
1684 saa_set (SAA7196_HUEC
, (unsigned char)
1685 ((pb
->picture
.hue
) >> 8) ^ 0x80, pb
);
1686 saa_set (SAA7196_CSAT
, (unsigned char)
1687 ((pb
->picture
.colour
) >> 9), pb
);
1688 saa_set (SAA7196_CONT
, (unsigned char)
1689 ((pb
->picture
.contrast
) >> 9), pb
);
1695 struct video_window vw
;
1696 struct video_clip clip
;
1699 DEBUG("PlanB: IOCTL VIDIOCSWIN\n");
1701 if(copy_from_user(&vw
,arg
,sizeof(vw
)))
1705 /* Stop overlay if running */
1706 suspend_overlay(pb
);
1707 pb
->win
.interlace
= (vw
.height
> pb
->maxlines
/2)? 1: 0;
1708 if (pb
->win
.x
!= vw
.x
||
1709 pb
->win
.y
!= vw
.y
||
1710 pb
->win
.width
!= vw
.width
||
1711 pb
->win
.height
!= vw
.height
||
1712 !pb
->cmd_buff_inited
) {
1715 pb
->win
.width
= vw
.width
;
1716 pb
->win
.height
= vw
.height
;
1719 /* Reset clip mask */
1720 memset ((void *) pb
->mask
, 0xff, (pb
->maxlines
1721 * ((PLANB_MAXPIXELS
+ 7) & ~7)) / 8);
1722 /* Add any clip rects */
1723 for (i
= 0; i
< vw
.clipcount
; i
++) {
1724 if (copy_from_user(&clip
, vw
.clips
+ i
,
1725 sizeof(struct video_clip
)))
1727 add_clip(pb
, &clip
);
1729 /* restart overlay if it was running */
1736 struct video_window vw
;
1738 DEBUG("PlanB: IOCTL VIDIOCGWIN\n");
1742 vw
.width
=pb
->win
.width
;
1743 vw
.height
=pb
->win
.height
;
1746 if(pb
->win
.interlace
)
1747 vw
.flags
|=VIDEO_WINDOW_INTERLACE
;
1748 if(copy_to_user(arg
,&vw
,sizeof(vw
)))
1755 IDEBUG("PlanB: IOCTL VIDIOCSYNC\n");
1757 if(copy_from_user((void *)&i
,arg
,sizeof(int)))
1760 IDEBUG("PlanB: sync to frame %d\n", i
);
1762 if(i
> (MAX_GBUFFERS
- 1) || i
< 0)
1765 switch (pb
->frame_stat
[i
]) {
1766 case GBUFFER_UNUSED
:
1768 case GBUFFER_GRABBING
:
1769 IDEBUG("PlanB: waiting for grab"
1771 interruptible_sleep_on(&pb
->capq
);
1772 if(signal_pending(current
))
1776 pb
->frame_stat
[i
] = GBUFFER_UNUSED
;
1782 case VIDIOCMCAPTURE
:
1784 struct video_mmap vm
;
1785 volatile unsigned int status
;
1787 IDEBUG("PlanB: IOCTL VIDIOCMCAPTURE\n");
1789 if(copy_from_user((void *) &vm
,(void *)arg
,sizeof(vm
)))
1791 status
= pb
->frame_stat
[vm
.frame
];
1792 if (status
!= GBUFFER_UNUSED
)
1795 return vgrab(pb
, &vm
);
1801 struct video_mbuf vm
;
1803 DEBUG("PlanB: IOCTL VIDIOCGMBUF\n");
1805 memset(&vm
, 0 , sizeof(vm
));
1806 vm
.size
= PLANB_MAX_FBUF
* MAX_GBUFFERS
;
1807 vm
.frames
= MAX_GBUFFERS
;
1808 for(i
= 0; i
<MAX_GBUFFERS
; i
++)
1809 vm
.offsets
[i
] = PLANB_MAX_FBUF
* i
;
1810 if(copy_to_user((void *)arg
, (void *)&vm
, sizeof(vm
)))
1815 case PLANBIOCGSAAREGS
:
1817 struct planb_saa_regs preg
;
1819 DEBUG("PlanB: IOCTL PLANBIOCGSAAREGS\n");
1821 if(copy_from_user(&preg
, arg
, sizeof(preg
)))
1823 if(preg
.addr
>= SAA7196_NUMREGS
)
1825 preg
.val
= saa_regs
[pb
->win
.norm
][preg
.addr
];
1826 if(copy_to_user((void *)arg
, (void *)&preg
,
1832 case PLANBIOCSSAAREGS
:
1834 struct planb_saa_regs preg
;
1836 DEBUG("PlanB: IOCTL PLANBIOCSSAAREGS\n");
1838 if(copy_from_user(&preg
, arg
, sizeof(preg
)))
1840 if(preg
.addr
>= SAA7196_NUMREGS
)
1842 saa_set (preg
.addr
, preg
.val
, pb
);
1848 struct planb_stat_regs pstat
;
1850 DEBUG("PlanB: IOCTL PLANBIOCGSTAT\n");
1852 pstat
.ch1_stat
= in_le32(&pb
->planb_base
->ch1
.status
);
1853 pstat
.ch2_stat
= in_le32(&pb
->planb_base
->ch2
.status
);
1854 pstat
.saa_stat0
= saa_status(0, pb
);
1855 pstat
.saa_stat1
= saa_status(1, pb
);
1857 if(copy_to_user((void *)arg
, (void *)&pstat
,
1863 case PLANBIOCSMODE
: {
1866 DEBUG("PlanB: IOCTL PLANBIOCSMODE\n");
1868 if(copy_from_user(&v
, arg
, sizeof(v
)))
1874 saa_set (SAA7196_STDC
,
1875 (saa_regs
[pb
->win
.norm
][SAA7196_STDC
] &
1878 case PLANB_VTR_MODE
:
1879 saa_set (SAA7196_STDC
,
1880 (saa_regs
[pb
->win
.norm
][SAA7196_STDC
] |
1890 case PLANBIOCGMODE
: {
1893 DEBUG("PlanB: IOCTL PLANBIOCGMODE\n");
1895 if(copy_to_user(arg
,&v
,sizeof(v
)))
1899 #ifdef PLANB_GSCANLINE
1900 case PLANBG_GRAB_BPL
: {
1901 int v
=pb
->gbytes_per_line
;
1903 DEBUG("PlanB: IOCTL PLANBG_GRAB_BPL\n");
1905 if(copy_to_user(arg
,&v
,sizeof(v
)))
1909 #endif /* PLANB_GSCANLINE */
1910 case PLANB_INTR_DEBUG
: {
1913 DEBUG("PlanB: IOCTL PLANB_INTR_DEBUG\n");
1915 if(copy_from_user(&i
, arg
, sizeof(i
)))
1918 /* avoid hang ups all together */
1919 for (i
= 0; i
< MAX_GBUFFERS
; i
++) {
1920 if(pb
->frame_stat
[i
] == GBUFFER_GRABBING
) {
1921 pb
->frame_stat
[i
] = GBUFFER_DONE
;
1926 wake_up_interruptible(&pb
->capq
);
1929 case PLANB_INV_REGS
: {
1931 struct planb_any_regs any
;
1933 DEBUG("PlanB: IOCTL PLANB_INV_REGS\n");
1935 if(copy_from_user(&any
, arg
, sizeof(any
)))
1937 if(any
.offset
< 0 || any
.offset
+ any
.bytes
> 0x400)
1941 for (i
= 0; i
< any
.bytes
; i
++) {
1943 in_8((unsigned char *)pb
->planb_base
1946 if(copy_to_user(arg
,&any
,sizeof(any
)))
1952 DEBUG("PlanB: Unimplemented IOCTL\n");
1953 return -ENOIOCTLCMD
;
1955 /* Some IOCTLs are currently unsupported on PlanB */
1956 case VIDIOCGTUNER
: {
1957 DEBUG("PlanB: IOCTL VIDIOCGTUNER\n");
1958 goto unimplemented
; }
1959 case VIDIOCSTUNER
: {
1960 DEBUG("PlanB: IOCTL VIDIOCSTUNER\n");
1961 goto unimplemented
; }
1963 DEBUG("PlanB: IOCTL VIDIOCSFREQ\n");
1964 goto unimplemented
; }
1966 DEBUG("PlanB: IOCTL VIDIOCGFREQ\n");
1967 goto unimplemented
; }
1969 DEBUG("PlanB: IOCTL VIDIOCKEY\n");
1970 goto unimplemented
; }
1971 case VIDIOCSAUDIO
: {
1972 DEBUG("PlanB: IOCTL VIDIOCSAUDIO\n");
1973 goto unimplemented
; }
1974 case VIDIOCGAUDIO
: {
1975 DEBUG("PlanB: IOCTL VIDIOCGAUDIO\n");
1976 goto unimplemented
; }
1978 DEBUG(" Unimplemented\n");
1979 return -ENOIOCTLCMD
;
1984 static int planb_mmap(struct vm_area_struct
*vma
, struct video_device
*dev
, const char *adr
, unsigned long size
)
1987 struct planb
*pb
= (struct planb
*)dev
;
1988 unsigned long start
= (unsigned long)adr
;
1990 if (size
> MAX_GBUFFERS
* PLANB_MAX_FBUF
)
1994 if((err
=grabbuf_alloc(pb
)))
1997 for (i
= 0; i
< pb
->rawbuf_size
; i
++) {
2000 pfn
= virt_to_phys((void *)pb
->rawbuf
[i
]) >> PAGE_SHIFT
;
2001 if (remap_pfn_range(vma
, start
, pfn
, PAGE_SIZE
, PAGE_SHARED
))
2004 if (size
<= PAGE_SIZE
)
2011 static struct video_device planb_template
=
2013 .owner
= THIS_MODULE
,
2014 .name
= PLANB_DEVICE_NAME
,
2015 .type
= VID_TYPE_OVERLAY
,
2016 .hardware
= VID_HARDWARE_PLANB
,
2018 .close
= planb_close
,
2020 .write
= planb_write
,
2021 .ioctl
= planb_ioctl
,
2022 .mmap
= planb_mmap
, /* mmap? */
2025 static int init_planb(struct planb
*pb
)
2027 unsigned char saa_rev
;
2030 memset ((void *) &pb
->win
, 0, sizeof (struct planb_window
));
2031 /* Simple sanity check */
2032 if(def_norm
>= NUM_SUPPORTED_NORM
|| def_norm
< 0) {
2033 printk(KERN_ERR
"PlanB: Option(s) invalid\n");
2036 pb
->win
.norm
= def_norm
;
2037 pb
->win
.mode
= PLANB_TV_MODE
; /* TV mode */
2038 pb
->win
.interlace
=1;
2041 pb
->win
.width
=768; /* 640 */
2042 pb
->win
.height
=576; /* 480 */
2045 btv
->win
.cropwidth
=768; /* 640 */
2046 btv
->win
.cropheight
=576; /* 480 */
2053 pb
->win
.color_fmt
=PLANB_COLOUR32
;
2054 pb
->win
.bpl
=1024*pb
->win
.bpp
;
2055 pb
->win
.swidth
=1024;
2056 pb
->win
.sheight
=768;
2057 #ifdef PLANB_GSCANLINE
2058 if((pb
->gbytes_per_line
= PLANB_MAXPIXELS
* 4) > PAGE_SIZE
2059 || (pb
->gbytes_per_line
<= 0))
2062 /* page align pb->gbytes_per_line for DMA purpose */
2063 for(i
= PAGE_SIZE
; pb
->gbytes_per_line
< (i
>>1);)
2065 pb
->gbytes_per_line
= i
;
2068 pb
->tab_size
= PLANB_MAXLINES
+ 40;
2070 init_MUTEX(&pb
->lock
);
2078 init_waitqueue_head(&pb
->suspendq
);
2079 pb
->cmd_buff_inited
= 0;
2080 pb
->frame_buffer_phys
= 0;
2082 /* Reset DMA controllers */
2083 planb_dbdma_stop(&pb
->planb_base
->ch2
);
2084 planb_dbdma_stop(&pb
->planb_base
->ch1
);
2086 saa_rev
= (saa_status(0, pb
) & 0xf0) >> 4;
2087 printk(KERN_INFO
"PlanB: SAA7196 video processor rev. %d\n", saa_rev
);
2088 /* Initialize the SAA registers in memory and on chip */
2091 /* clear interrupt mask */
2092 pb
->intr_mask
= PLANB_CLR_IRQ
;
2094 result
= request_irq(pb
->irq
, planb_irq
, 0, "PlanB", (void *)pb
);
2096 if (result
==-EINVAL
)
2097 printk(KERN_ERR
"PlanB: Bad irq number (%d) "
2098 "or handler\n", (int)pb
->irq
);
2099 else if (result
==-EBUSY
)
2100 printk(KERN_ERR
"PlanB: I don't know why, "
2101 "but IRQ %d is busy\n", (int)pb
->irq
);
2104 disable_irq(pb
->irq
);
2106 /* Now add the template and register the device unit. */
2107 memcpy(&pb
->video_dev
,&planb_template
,sizeof(planb_template
));
2109 pb
->picture
.brightness
=0x90<<8;
2110 pb
->picture
.contrast
= 0x70 << 8;
2111 pb
->picture
.colour
= 0x70<<8;
2112 pb
->picture
.hue
= 0x8000;
2113 pb
->picture
.whiteness
= 0;
2114 pb
->picture
.depth
= pb
->win
.depth
;
2116 pb
->frame_stat
=NULL
;
2117 init_waitqueue_head(&pb
->capq
);
2118 for(i
=0; i
<MAX_GBUFFERS
; i
++) {
2119 pb
->gbuf_idx
[i
] = PLANB_MAX_FBUF
* i
/ PAGE_SIZE
;
2123 pb
->cap_cmd
[i
]=NULL
;
2124 #ifndef PLANB_GSCANLINE
2125 pb
->l_fr_addr_idx
[i
] = MAX_GBUFFERS
* (PLANB_MAX_FBUF
2126 / PAGE_SIZE
+ 1) + MAX_LNUM
* i
;
2134 /* enable interrupts */
2135 out_le32(&pb
->planb_base
->intr_stat
, PLANB_CLR_IRQ
);
2136 pb
->intr_mask
= PLANB_FRM_IRQ
;
2137 enable_irq(pb
->irq
);
2139 if(video_register_device(&pb
->video_dev
, VFL_TYPE_GRABBER
, video_nr
)<0)
2146 * Scan for a PlanB controller, request the irq and map the io memory
2149 static int find_planb(void)
2152 struct device_node
*planb_devices
;
2153 unsigned char dev_fn
, confreg
, bus
;
2154 unsigned int old_base
, new_base
;
2156 struct pci_dev
*pdev
;
2159 if (_machine
!= _MACH_Pmac
)
2162 planb_devices
= find_devices("planb");
2163 if (planb_devices
== 0) {
2165 printk(KERN_WARNING
"PlanB: no device found!\n");
2169 if (planb_devices
->next
!= NULL
)
2170 printk(KERN_ERR
"Warning: only using first PlanB device!\n");
2174 if (planb_devices
->n_addrs
!= 1) {
2175 printk (KERN_WARNING
"PlanB: expecting 1 address for planb "
2176 "(got %d)", planb_devices
->n_addrs
);
2180 if (planb_devices
->n_intrs
== 0) {
2181 printk(KERN_WARNING
"PlanB: no intrs for device %s\n",
2182 planb_devices
->full_name
);
2185 irq
= planb_devices
->intrs
[0].line
;
2188 /* Initialize PlanB's PCI registers */
2190 /* There is a bug with the way OF assigns addresses
2191 to the devices behind the chaos bridge.
2192 control needs only 0x1000 of space, but decodes only
2193 the upper 16 bits. It therefore occupies a full 64K.
2194 OF assigns the planb controller memory within this space;
2195 so we need to change that here in order to access planb. */
2197 /* We remap to 0xf1000000 in hope that nobody uses it ! */
2199 bus
= (planb_devices
->addrs
[0].space
>> 16) & 0xff;
2200 dev_fn
= (planb_devices
->addrs
[0].space
>> 8) & 0xff;
2201 confreg
= planb_devices
->addrs
[0].space
& 0xff;
2202 old_base
= planb_devices
->addrs
[0].address
;
2203 new_base
= 0xf1000000;
2205 DEBUG("PlanB: Found on bus %d, dev %d, func %d, "
2206 "membase 0x%x (base reg. 0x%x)\n",
2207 bus
, PCI_SLOT(dev_fn
), PCI_FUNC(dev_fn
), old_base
, confreg
);
2209 pdev
= pci_find_slot (bus
, dev_fn
);
2211 printk(KERN_ERR
"planb: cannot find slot\n");
2215 /* Enable response in memory space, bus mastering,
2216 use memory write and invalidate */
2217 rc
= pci_enable_device(pdev
);
2219 printk(KERN_ERR
"planb: cannot enable PCI device %s\n",
2223 rc
= pci_set_mwi(pdev
);
2225 printk(KERN_ERR
"planb: cannot enable MWI on PCI device %s\n",
2227 goto err_out_disable
;
2229 pci_set_master(pdev
);
2231 /* Set the new base address */
2232 pci_write_config_dword (pdev
, confreg
, new_base
);
2234 planb_regs
= (volatile struct planb_registers
*)
2235 ioremap (new_base
, 0x400);
2236 pb
->planb_base
= planb_regs
;
2237 pb
->planb_base_phys
= (struct planb_registers
*)new_base
;
2243 pci_disable_device(pdev
);
2245 /* FIXME handle error */ /* comment moved from pci_find_slot, above */
2249 static void release_planb(void)
2254 for (i
=0;i
<planb_num
; i
++)
2258 /* stop and flash DMAs unconditionally */
2259 planb_dbdma_stop(&pb
->planb_base
->ch2
);
2260 planb_dbdma_stop(&pb
->planb_base
->ch1
);
2262 /* clear and free interrupts */
2263 pb
->intr_mask
= PLANB_CLR_IRQ
;
2264 out_le32 (&pb
->planb_base
->intr_stat
, PLANB_CLR_IRQ
);
2265 free_irq(pb
->irq
, pb
);
2267 /* make sure all allocated memory are freed */
2268 planb_prepare_close(pb
);
2270 printk(KERN_INFO
"PlanB: unregistering with v4l\n");
2271 video_unregister_device(&pb
->video_dev
);
2273 /* note that iounmap() does nothing on the PPC right now */
2274 iounmap ((void *)pb
->planb_base
);
2278 static int __init
init_planbs(void)
2282 if (find_planb()<=0)
2285 for (i
=0; i
<planb_num
; i
++) {
2286 if (init_planb(&planbs
[i
])<0) {
2287 printk(KERN_ERR
"PlanB: error registering device %d"
2292 printk(KERN_INFO
"PlanB: registered device %d with v4l\n", i
);
2297 static void __exit
exit_planbs(void)
2302 module_init(init_planbs
);
2303 module_exit(exit_planbs
);