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/version.h>
31 #include <linux/init.h>
32 #include <linux/errno.h>
33 #include <linux/module.h>
34 #include <linux/kernel.h>
35 #include <linux/major.h>
36 #include <linux/malloc.h>
37 #include <linux/types.h>
38 #include <linux/pci.h>
39 #include <linux/delay.h>
40 #include <linux/vmalloc.h>
42 #include <linux/sched.h>
43 #include <linux/wrapper.h>
44 #include <linux/tqueue.h>
45 #include <linux/videodev.h>
46 #include <asm/uaccess.h>
49 #include <asm/dbdma.h>
50 #include <asm/pgtable.h>
58 /* Would you mind for some ugly debugging? */
59 //#define DEBUG(x...) printk(KERN_DEBUG ## x) /* Debug driver */
60 #define DEBUG(x...) /* Don't debug driver */
61 //#define IDEBUG(x...) printk(KERN_DEBUG ## x) /* Debug interrupt part */
62 #define IDEBUG(x...) /* Don't debug interrupt part */
64 /* Ever seen a Mac with more than 1 of these? */
68 static struct planb planbs
[PLANB_MAX
];
69 static volatile struct planb_registers
*planb_regs
;
71 static int def_norm
= PLANB_DEF_NORM
; /* default norm */
73 MODULE_PARM(def_norm
, "i");
74 MODULE_PARM_DESC(def_norm
, "Default startup norm (0=PAL, 1=NTSC, 2=SECAM)");
76 /* ------------------ PlanB Exported Functions ------------------ */
77 static long planb_write(struct video_device
*, const char *, unsigned long, int);
78 static long planb_read(struct video_device
*, char *, unsigned long, int);
79 static int planb_open(struct video_device
*, int);
80 static void planb_close(struct video_device
*);
81 static int planb_ioctl(struct video_device
*, unsigned int, void *);
82 static int planb_init_done(struct video_device
*);
83 static int planb_mmap(struct video_device
*, const char *, unsigned long);
84 static void planb_irq(int, void *, struct pt_regs
*);
85 static void release_planb(void);
86 int init_planbs(struct video_init
*);
88 /* ------------------ PlanB Internal Functions ------------------ */
89 static int planb_prepare_open(struct planb
*);
90 static void planb_prepare_close(struct planb
*);
91 static void saa_write_reg(unsigned char, unsigned char);
92 static unsigned char saa_status(int, struct planb
*);
93 static void saa_set(unsigned char, unsigned char, struct planb
*);
94 static void saa_init_regs(struct planb
*);
95 static int grabbuf_alloc(struct planb
*);
96 static int vgrab(struct planb
*, struct video_mmap
*);
97 static void add_clip(struct planb
*, struct video_clip
*);
98 static void fill_cmd_buff(struct planb
*);
99 static void cmd_buff(struct planb
*);
100 static volatile struct dbdma_cmd
*setup_grab_cmd(int, struct planb
*);
101 static void overlay_start(struct planb
*);
102 static void overlay_stop(struct planb
*);
103 static inline void tab_cmd_dbdma(volatile struct dbdma_cmd
*, unsigned short,
105 static inline void tab_cmd_store(volatile struct dbdma_cmd
*, unsigned int,
107 static inline void tab_cmd_gen(volatile struct dbdma_cmd
*, unsigned short,
108 unsigned short, unsigned int, unsigned int);
109 static int init_planb(struct planb
*);
110 static int find_planb(void);
111 static void planb_pre_capture(int, int, struct planb
*);
112 static volatile struct dbdma_cmd
*cmd_geo_setup(volatile struct dbdma_cmd
*,
113 int, int, int, int, int, struct planb
*);
114 static inline void planb_dbdma_stop(volatile struct dbdma_regs
*);
115 static unsigned int saa_geo_setup(int, int, int, int, struct planb
*);
116 static inline int overlay_is_active(struct planb
*);
118 /*******************************/
119 /* Memory management functions */
120 /*******************************/
122 static int grabbuf_alloc(struct planb
*pb
)
126 npage
= MAX_GBUFFERS
* ((PLANB_MAX_FBUF
/ PAGE_SIZE
+ 1)
127 #ifndef PLANB_GSCANLINE
129 #endif /* PLANB_GSCANLINE */
131 if ((pb
->rawbuf
= (unsigned char**) kmalloc (npage
132 * sizeof(unsigned long), GFP_KERNEL
)) == 0)
134 for (i
= 0; i
< npage
; i
++) {
135 pb
->rawbuf
[i
] = (unsigned char *)__get_free_pages(GFP_KERNEL
139 set_bit(PG_reserved
, &mem_map
[MAP_NR(pb
->rawbuf
[i
])].flags
);
142 printk(KERN_DEBUG
"PlanB: init_grab: grab buffer not allocated\n");
144 clear_bit(PG_reserved
,
145 &mem_map
[MAP_NR(pb
->rawbuf
[i
])].flags
);
146 free_pages((unsigned long)pb
->rawbuf
[i
], 0);
151 pb
->rawbuf_size
= npage
;
155 /*****************************/
156 /* Hardware access functions */
157 /*****************************/
159 static void saa_write_reg(unsigned char addr
, unsigned char val
)
161 planb_regs
->saa_addr
= addr
; eieio();
162 planb_regs
->saa_regval
= val
; eieio();
166 /* return status byte 0 or 1: */
167 static unsigned char saa_status(int byte
, struct planb
*pb
)
169 saa_regs
[pb
->win
.norm
][SAA7196_STDC
] =
170 (saa_regs
[pb
->win
.norm
][SAA7196_STDC
] & ~2) | ((byte
& 1) << 1);
171 saa_write_reg (SAA7196_STDC
, saa_regs
[pb
->win
.norm
][SAA7196_STDC
]);
173 /* Let's wait 30msec for this one */
174 current
->state
= TASK_INTERRUPTIBLE
;
175 #if LINUX_VERSION_CODE >= 0x02017F
176 schedule_timeout(30 * HZ
/ 1000);
178 current
->timeout
= jiffies
+ 30 * HZ
/ 1000; /* 30 ms */;
182 return (unsigned char)in_8 (&planb_regs
->saa_status
);
185 static void saa_set(unsigned char addr
, unsigned char val
, struct planb
*pb
)
187 if(saa_regs
[pb
->win
.norm
][addr
] != val
) {
188 saa_regs
[pb
->win
.norm
][addr
] = val
;
189 saa_write_reg (addr
, val
);
194 static void saa_init_regs(struct planb
*pb
)
198 for (i
= 0; i
< SAA7196_NUMREGS
; i
++)
199 saa_write_reg (i
, saa_regs
[pb
->win
.norm
][i
]);
202 static unsigned int saa_geo_setup(int width
, int height
, int interlace
, int bpp
,
205 int ht
, norm
= pb
->win
.norm
;
209 /* RGB555+a 1x16-bit + 16-bit transparent */
210 saa_regs
[norm
][SAA7196_FMTS
] &= ~0x3;
214 /* RGB888 1x24-bit + 8-bit transparent */
215 saa_regs
[norm
][SAA7196_FMTS
] &= ~0x1;
216 saa_regs
[norm
][SAA7196_FMTS
] |= 0x2;
221 ht
= (interlace
? height
/ 2 : height
);
222 saa_regs
[norm
][SAA7196_OUTPIX
] = (unsigned char) (width
& 0x00ff);
223 saa_regs
[norm
][SAA7196_HFILT
] = (saa_regs
[norm
][SAA7196_HFILT
] & ~0x3)
224 | (width
>> 8 & 0x3);
225 saa_regs
[norm
][SAA7196_OUTLINE
] = (unsigned char) (ht
& 0xff);
226 saa_regs
[norm
][SAA7196_VYP
] = (saa_regs
[norm
][SAA7196_VYP
] & ~0x3)
228 /* feed both fields if interlaced, or else feed only even fields */
229 saa_regs
[norm
][SAA7196_FMTS
] = (interlace
) ?
230 (saa_regs
[norm
][SAA7196_FMTS
] & ~0x60)
231 : (saa_regs
[norm
][SAA7196_FMTS
] | 0x60);
232 /* transparent mode; extended format enabled */
233 saa_regs
[norm
][SAA7196_DPATH
] |= 0x3;
238 /***************************/
239 /* DBDMA support functions */
240 /***************************/
242 static inline void planb_dbdma_restart(volatile struct dbdma_regs
*ch
)
244 out_le32(&ch
->control
, PLANB_CLR(RUN
));
245 out_le32(&ch
->control
, PLANB_SET(RUN
|WAKE
) | PLANB_CLR(PAUSE
));
248 static inline void planb_dbdma_stop(volatile struct dbdma_regs
*ch
)
252 out_le32(&ch
->control
, PLANB_CLR(RUN
) | PLANB_SET(FLUSH
));
253 while((in_le32(&ch
->status
) == (ACTIVE
| FLUSH
)) && (i
< 999)) {
254 IDEBUG("PlanB: waiting for DMA to stop\n");
259 static inline void tab_cmd_dbdma(volatile struct dbdma_cmd
*ch
,
260 unsigned short command
, unsigned int cmd_dep
)
262 st_le16(&ch
->command
, command
);
263 st_le32(&ch
->cmd_dep
, cmd_dep
);
266 static inline void tab_cmd_store(volatile struct dbdma_cmd
*ch
,
267 unsigned int phy_addr
, unsigned int cmd_dep
)
269 st_le16(&ch
->command
, STORE_WORD
| KEY_SYSTEM
);
270 st_le16(&ch
->req_count
, 4);
271 st_le32(&ch
->phy_addr
, phy_addr
);
272 st_le32(&ch
->cmd_dep
, cmd_dep
);
275 static inline void tab_cmd_gen(volatile struct dbdma_cmd
*ch
,
276 unsigned short command
, unsigned short req_count
,
277 unsigned int phy_addr
, unsigned int cmd_dep
)
279 st_le16(&ch
->command
, command
);
280 st_le16(&ch
->req_count
, req_count
);
281 st_le32(&ch
->phy_addr
, phy_addr
);
282 st_le32(&ch
->cmd_dep
, cmd_dep
);
285 static volatile struct dbdma_cmd
*cmd_geo_setup(
286 volatile struct dbdma_cmd
*c1
, int width
, int height
, int interlace
,
287 int bpp
, int clip
, struct planb
*pb
)
289 int norm
= pb
->win
.norm
;
291 if((saa_geo_setup(width
, height
, interlace
, bpp
, pb
)) != 0)
292 return (volatile struct dbdma_cmd
*)NULL
;
293 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->saa_addr
),
295 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->saa_regval
),
296 saa_regs
[norm
][SAA7196_FMTS
]);
297 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->saa_addr
),
299 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->saa_regval
),
300 saa_regs
[norm
][SAA7196_DPATH
]);
301 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->even
),
302 bpp
| ((clip
)? PLANB_CLIPMASK
: 0));
303 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->odd
),
304 bpp
| ((clip
)? PLANB_CLIPMASK
: 0));
305 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->saa_addr
),
307 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->saa_regval
),
308 saa_regs
[norm
][SAA7196_OUTPIX
]);
309 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->saa_addr
),
311 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->saa_regval
),
312 saa_regs
[norm
][SAA7196_HFILT
]);
313 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->saa_addr
),
315 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->saa_regval
),
316 saa_regs
[norm
][SAA7196_OUTLINE
]);
317 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->saa_addr
),
319 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->saa_regval
),
320 saa_regs
[norm
][SAA7196_VYP
]);
324 /******************************/
325 /* misc. supporting functions */
326 /******************************/
328 static void __planb_wait(struct planb
*pb
)
330 DECLARE_WAITQUEUE(wait
, current
);
332 add_wait_queue(&pb
->lockq
, &wait
);
334 set_current_state(TASK_UNINTERRUPTIBLE
);
339 remove_wait_queue(&pb
->lockq
, &wait
);
340 current
->state
= TASK_RUNNING
;
343 static inline void planb_wait(struct planb
*pb
)
345 DEBUG("PlanB: planb_wait\n");
350 static inline void planb_lock(struct planb
*pb
)
352 DEBUG("PlanB: planb_lock\n");
358 static inline void planb_unlock(struct planb
*pb
)
360 DEBUG("PlanB: planb_unlock\n");
369 static int planb_prepare_open(struct planb
*pb
)
373 /* allocate memory for two plus alpha command buffers (size: max lines,
374 plus 40 commands handling, plus 1 alignment), plus dummy command buf,
375 plus clipmask buffer, plus frame grabbing status */
376 size
= (pb
->tab_size
*(2+MAX_GBUFFERS
*TAB_FACTOR
)+1+MAX_GBUFFERS
377 * PLANB_DUMMY
)*sizeof(struct dbdma_cmd
)
378 +(PLANB_MAXLINES
*((PLANB_MAXPIXELS
+7)& ~7))/8
379 +MAX_GBUFFERS
*sizeof(unsigned int);
380 if ((pb
->priv_space
= kmalloc (size
, GFP_KERNEL
)) == 0)
382 memset ((void *) pb
->priv_space
, 0, size
);
383 pb
->overlay_last1
= pb
->ch1_cmd
= (volatile struct dbdma_cmd
*)
384 DBDMA_ALIGN (pb
->priv_space
);
385 pb
->overlay_last2
= pb
->ch2_cmd
= pb
->ch1_cmd
+ pb
->tab_size
;
386 pb
->ch1_cmd_phys
= virt_to_bus(pb
->ch1_cmd
);
387 pb
->cap_cmd
[0] = pb
->ch2_cmd
+ pb
->tab_size
;
388 pb
->pre_cmd
[0] = pb
->cap_cmd
[0] + pb
->tab_size
* TAB_FACTOR
;
389 for (i
= 1; i
< MAX_GBUFFERS
; i
++) {
390 pb
->cap_cmd
[i
] = pb
->pre_cmd
[i
-1] + PLANB_DUMMY
;
391 pb
->pre_cmd
[i
] = pb
->cap_cmd
[i
] + pb
->tab_size
* TAB_FACTOR
;
393 pb
->frame_stat
=(volatile unsigned int *)(pb
->pre_cmd
[MAX_GBUFFERS
-1]
395 pb
->mask
= (unsigned char *)(pb
->frame_stat
+MAX_GBUFFERS
);
400 for (i
= 0; i
< MAX_GBUFFERS
; i
++) {
401 pb
->frame_stat
[i
] = GBUFFER_UNUSED
;
405 pb
->gnorm_switch
[i
] = 0;
406 #ifndef PLANB_GSCANLINE
409 #endif /* PLANB_GSCANLINE */
414 pb
->prev_last_fr
= -999;
416 /* Reset DMA controllers */
417 planb_dbdma_stop(&pb
->planb_base
->ch2
);
418 planb_dbdma_stop(&pb
->planb_base
->ch1
);
423 static void planb_prepare_close(struct planb
*pb
)
427 /* make sure the dma's are idle */
428 planb_dbdma_stop(&pb
->planb_base
->ch2
);
429 planb_dbdma_stop(&pb
->planb_base
->ch1
);
430 /* free kernel memory of command buffers */
431 if(pb
->priv_space
!= 0) {
432 kfree (pb
->priv_space
);
434 pb
->cmd_buff_inited
= 0;
437 for (i
= 0; i
< pb
->rawbuf_size
; i
++) {
438 clear_bit(PG_reserved
,
439 &mem_map
[MAP_NR(pb
->rawbuf
[i
])].flags
);
440 free_pages((unsigned long)pb
->rawbuf
[i
], 0);
447 /*****************************/
448 /* overlay support functions */
449 /*****************************/
451 static void overlay_start(struct planb
*pb
)
454 DEBUG("PlanB: overlay_start()\n");
456 if(ACTIVE
& in_le32(&pb
->planb_base
->ch1
.status
)) {
458 DEBUG("PlanB: presumably, grabbing is in progress...\n");
460 planb_dbdma_stop(&pb
->planb_base
->ch2
);
461 out_le32 (&pb
->planb_base
->ch2
.cmdptr
,
462 virt_to_bus(pb
->ch2_cmd
));
463 planb_dbdma_restart(&pb
->planb_base
->ch2
);
464 st_le16 (&pb
->ch1_cmd
->command
, DBDMA_NOP
);
465 tab_cmd_dbdma(pb
->last_cmd
[pb
->last_fr
],
466 DBDMA_NOP
| BR_ALWAYS
,
467 virt_to_bus(pb
->ch1_cmd
));
469 pb
->prev_last_fr
= pb
->last_fr
;
471 if(!(ACTIVE
& in_le32(&pb
->planb_base
->ch1
.status
))) {
472 IDEBUG("PlanB: became inactive "
473 "in the mean time... reactivating\n");
474 planb_dbdma_stop(&pb
->planb_base
->ch1
);
475 out_le32 (&pb
->planb_base
->ch1
.cmdptr
,
476 virt_to_bus(pb
->ch1_cmd
));
477 planb_dbdma_restart(&pb
->planb_base
->ch1
);
481 DEBUG("PlanB: currently idle, so can do whatever\n");
483 planb_dbdma_stop(&pb
->planb_base
->ch2
);
484 planb_dbdma_stop(&pb
->planb_base
->ch1
);
485 st_le32 (&pb
->planb_base
->ch2
.cmdptr
,
486 virt_to_bus(pb
->ch2_cmd
));
487 st_le32 (&pb
->planb_base
->ch1
.cmdptr
,
488 virt_to_bus(pb
->ch1_cmd
));
489 out_le16 (&pb
->ch1_cmd
->command
, DBDMA_NOP
);
490 planb_dbdma_restart(&pb
->planb_base
->ch2
);
491 planb_dbdma_restart(&pb
->planb_base
->ch1
);
497 static void overlay_stop(struct planb
*pb
)
499 DEBUG("PlanB: overlay_stop()\n");
501 if(pb
->last_fr
== -1) {
503 DEBUG("PlanB: no grabbing, it seems...\n");
505 planb_dbdma_stop(&pb
->planb_base
->ch2
);
506 planb_dbdma_stop(&pb
->planb_base
->ch1
);
508 } else if(pb
->last_fr
== -2) {
509 unsigned int cmd_dep
;
510 tab_cmd_dbdma(pb
->cap_cmd
[pb
->prev_last_fr
], DBDMA_STOP
, 0);
512 cmd_dep
= (unsigned int)in_le32(&pb
->overlay_last1
->cmd_dep
);
513 if(overlay_is_active(pb
)) {
515 DEBUG("PlanB: overlay is currently active\n");
517 planb_dbdma_stop(&pb
->planb_base
->ch2
);
518 planb_dbdma_stop(&pb
->planb_base
->ch1
);
519 if(cmd_dep
!= pb
->ch1_cmd_phys
) {
520 out_le32(&pb
->planb_base
->ch1
.cmdptr
,
521 virt_to_bus(pb
->overlay_last1
));
522 planb_dbdma_restart(&pb
->planb_base
->ch1
);
525 pb
->last_fr
= pb
->prev_last_fr
;
526 pb
->prev_last_fr
= -999;
531 static void suspend_overlay(struct planb
*pb
)
534 struct dbdma_cmd last
;
536 DEBUG("PlanB: suspend_overlay: %d\n", pb
->suspend
);
540 if(ACTIVE
& in_le32(&pb
->planb_base
->ch1
.status
)) {
541 if(pb
->last_fr
== -2) {
542 fr
= pb
->prev_last_fr
;
543 memcpy(&last
, (void*)pb
->last_cmd
[fr
], sizeof(last
));
544 tab_cmd_dbdma(pb
->last_cmd
[fr
], DBDMA_STOP
, 0);
546 if(overlay_is_active(pb
)) {
547 planb_dbdma_stop(&pb
->planb_base
->ch2
);
548 planb_dbdma_stop(&pb
->planb_base
->ch1
);
549 pb
->suspended
.overlay
= 1;
550 pb
->suspended
.frame
= fr
;
551 memcpy(&pb
->suspended
.cmd
, &last
, sizeof(last
));
555 pb
->suspended
.overlay
= 0;
556 pb
->suspended
.frame
= fr
;
557 memcpy(&pb
->suspended
.cmd
, &last
, sizeof(last
));
561 static void resume_overlay(struct planb
*pb
)
564 DEBUG("PlanB: resume_overlay: %d\n", pb
->suspend
);
568 if(pb
->suspended
.frame
!= -1) {
569 memcpy((void*)pb
->last_cmd
[pb
->suspended
.frame
],
570 &pb
->suspended
.cmd
, sizeof(pb
->suspended
.cmd
));
572 if(ACTIVE
& in_le32(&pb
->planb_base
->ch1
.status
)) {
575 if(pb
->suspended
.overlay
) {
577 DEBUG("PlanB: overlay being resumed\n");
579 st_le16 (&pb
->ch1_cmd
->command
, DBDMA_NOP
);
580 st_le16 (&pb
->ch2_cmd
->command
, DBDMA_NOP
);
581 /* Set command buffer addresses */
582 st_le32(&pb
->planb_base
->ch1
.cmdptr
,
583 virt_to_bus(pb
->overlay_last1
));
584 out_le32(&pb
->planb_base
->ch2
.cmdptr
,
585 virt_to_bus(pb
->overlay_last2
));
586 /* Start the DMA controller */
587 out_le32 (&pb
->planb_base
->ch2
.control
,
588 PLANB_CLR(PAUSE
) | PLANB_SET(RUN
|WAKE
));
589 out_le32 (&pb
->planb_base
->ch1
.control
,
590 PLANB_CLR(PAUSE
) | PLANB_SET(RUN
|WAKE
));
591 } else if(pb
->suspended
.frame
!= -1) {
592 out_le32(&pb
->planb_base
->ch1
.cmdptr
,
593 virt_to_bus(pb
->last_cmd
[pb
->suspended
.frame
]));
594 out_le32 (&pb
->planb_base
->ch1
.control
,
595 PLANB_CLR(PAUSE
) | PLANB_SET(RUN
|WAKE
));
600 wake_up_interruptible(&pb
->suspendq
);
603 static void add_clip(struct planb
*pb
, struct video_clip
*clip
)
605 volatile unsigned char *base
;
606 int xc
= clip
->x
, yc
= clip
->y
;
607 int wc
= clip
->width
, hc
= clip
->height
;
608 int ww
= pb
->win
.width
, hw
= pb
->win
.height
;
609 int x
, y
, xtmp1
, xtmp2
;
611 DEBUG("PlanB: clip %dx%d+%d+%d\n", wc
, hc
, xc
, yc
);
623 if(wc
<= 0) /* Nothing to do */
628 for (y
= yc
; y
< yc
+hc
; y
++) {
631 base
= pb
->mask
+ y
*96;
632 if(xc
!= 0 || wc
>= 8)
633 *(base
+ xtmp1
) &= (unsigned char)(0x00ff &
635 for (x
= xtmp1
+ 1; x
< xtmp2
; x
++) {
639 *(base
+ xtmp2
) &= (unsigned char)(0x00ff >>
646 static void fill_cmd_buff(struct planb
*pb
)
649 volatile struct dbdma_cmd last
;
651 DEBUG("PlanB: fill_cmd_buff()\n");
653 if(pb
->overlay_last1
!= pb
->ch1_cmd
) {
655 last
= *(pb
->overlay_last1
);
657 memset ((void *) pb
->ch1_cmd
, 0, 2 * pb
->tab_size
658 * sizeof(struct dbdma_cmd
));
661 *(pb
->overlay_last1
) = last
;
662 if(pb
->suspended
.overlay
) {
663 unsigned long jump_addr
= in_le32(&pb
->overlay_last1
->cmd_dep
);
664 if(jump_addr
!= pb
->ch1_cmd_phys
) {
667 DEBUG("PlanB: adjusting ch1's jump address\n");
669 for(i
= 0; i
< MAX_GBUFFERS
; i
++) {
670 if(pb
->need_pre_capture
[i
]) {
671 if(jump_addr
== virt_to_bus(pb
->pre_cmd
[i
]))
674 if(jump_addr
== virt_to_bus(pb
->cap_cmd
[i
]))
679 DEBUG("PlanB: not found...\n");
683 if(pb
->need_pre_capture
[i
])
684 out_le32(&pb
->pre_cmd
[i
]->phy_addr
,
685 virt_to_bus(pb
->overlay_last1
));
687 out_le32(&pb
->cap_cmd
[i
]->phy_addr
,
688 virt_to_bus(pb
->overlay_last1
));
692 pb
->cmd_buff_inited
= 1;
697 static void cmd_buff(struct planb
*pb
)
699 int i
, bpp
, count
, nlines
, stepsize
, interlace
;
700 unsigned long base
, jump
, addr_com
, addr_dep
;
701 volatile struct dbdma_cmd
*c1
= pb
->ch1_cmd
;
702 volatile struct dbdma_cmd
*c2
= pb
->ch2_cmd
;
704 interlace
= pb
->win
.interlace
;
706 count
= (bpp
* ((pb
->win
.x
+ pb
->win
.width
> pb
->win
.swidth
) ?
707 (pb
->win
.swidth
- pb
->win
.x
) : pb
->win
.width
));
708 nlines
= ((pb
->win
.y
+ pb
->win
.height
> pb
->win
.sheight
) ?
709 (pb
->win
.sheight
- pb
->win
.y
) : pb
->win
.height
);
713 /* Preamble commands: */
714 addr_com
= virt_to_bus(c1
);
715 addr_dep
= virt_to_bus(&c1
->cmd_dep
);
716 tab_cmd_dbdma(c1
++, DBDMA_NOP
, 0);
717 jump
= virt_to_bus(c1
+16); /* 14 by cmd_geo_setup() and 2 for padding */
718 if((c1
= cmd_geo_setup(c1
, pb
->win
.width
, pb
->win
.height
, interlace
,
719 bpp
, 1, pb
)) == NULL
) {
720 printk(KERN_WARNING
"PlanB: encountered serious problems\n");
721 tab_cmd_dbdma(pb
->ch1_cmd
+ 1, DBDMA_STOP
, 0);
722 tab_cmd_dbdma(pb
->ch2_cmd
+ 1, DBDMA_STOP
, 0);
725 tab_cmd_store(c1
++, addr_com
, (unsigned)(DBDMA_NOP
| BR_ALWAYS
) << 16);
726 tab_cmd_store(c1
++, addr_dep
, jump
);
727 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->ch1
.wait_sel
),
728 PLANB_SET(FIELD_SYNC
));
729 /* (1) wait for field sync to be set */
730 tab_cmd_dbdma(c1
++, DBDMA_NOP
| WAIT_IFCLR
, 0);
731 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->ch1
.br_sel
),
732 PLANB_SET(ODD_FIELD
));
733 /* wait for field sync to be cleared */
734 tab_cmd_dbdma(c1
++, DBDMA_NOP
| WAIT_IFSET
, 0);
735 /* if not odd field, wait until field sync is set again */
736 tab_cmd_dbdma(c1
, DBDMA_NOP
| BR_IFSET
, virt_to_bus(c1
-3)); c1
++;
737 /* assert ch_sync to ch2 */
738 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->ch2
.control
),
740 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->ch1
.br_sel
),
741 PLANB_SET(DMA_ABORT
));
743 base
= (pb
->frame_buffer_phys
+ pb
->offset
+ pb
->win
.y
* (pb
->win
.bpl
744 + pb
->win
.pad
) + pb
->win
.x
* bpp
);
748 jump
= virt_to_bus(c1
+ (nlines
+ 1) / 2);
751 jump
= virt_to_bus(c1
+ nlines
);
754 /* even field data: */
755 for (i
=0; i
< nlines
; i
+= stepsize
, c1
++)
756 tab_cmd_gen(c1
, INPUT_MORE
| KEY_STREAM0
| BR_IFSET
,
757 count
, base
+ i
* (pb
->win
.bpl
+ pb
->win
.pad
), jump
);
759 /* For non-interlaced, we use even fields only */
761 goto cmd_tab_data_end
;
763 /* Resync to odd field */
764 /* (2) wait for field sync to be set */
765 tab_cmd_dbdma(c1
++, DBDMA_NOP
| WAIT_IFCLR
, 0);
766 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->ch1
.br_sel
),
767 PLANB_SET(ODD_FIELD
));
768 /* wait for field sync to be cleared */
769 tab_cmd_dbdma(c1
++, DBDMA_NOP
| WAIT_IFSET
, 0);
770 /* if not odd field, wait until field sync is set again */
771 tab_cmd_dbdma(c1
, DBDMA_NOP
| BR_IFCLR
, virt_to_bus(c1
-3)); c1
++;
772 /* assert ch_sync to ch2 */
773 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->ch2
.control
),
775 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->ch1
.br_sel
),
776 PLANB_SET(DMA_ABORT
));
778 /* odd field data: */
779 jump
= virt_to_bus(c1
+ nlines
/ 2);
780 for (i
=1; i
< nlines
; i
+= stepsize
, c1
++)
781 tab_cmd_gen(c1
, INPUT_MORE
| KEY_STREAM0
| BR_IFSET
, count
,
782 base
+ i
* (pb
->win
.bpl
+ pb
->win
.pad
), jump
);
784 /* And jump back to the start */
786 pb
->overlay_last1
= c1
; /* keep a pointer to the last command */
787 tab_cmd_dbdma(c1
, DBDMA_NOP
| BR_ALWAYS
, virt_to_bus(pb
->ch1_cmd
));
789 /* Clipmask command buffer */
791 /* Preamble commands: */
792 tab_cmd_dbdma(c2
++, DBDMA_NOP
, 0);
793 tab_cmd_store(c2
++, (unsigned)(&pb
->planb_base_phys
->ch2
.wait_sel
),
795 /* wait until ch1 asserts ch_sync */
796 tab_cmd_dbdma(c2
++, DBDMA_NOP
| WAIT_IFCLR
, 0);
797 /* clear ch_sync asserted by ch1 */
798 tab_cmd_store(c2
++, (unsigned)(&pb
->planb_base_phys
->ch2
.control
),
800 tab_cmd_store(c2
++, (unsigned)(&pb
->planb_base_phys
->ch2
.wait_sel
),
801 PLANB_SET(FIELD_SYNC
));
802 tab_cmd_store(c2
++, (unsigned)(&pb
->planb_base_phys
->ch2
.br_sel
),
803 PLANB_SET(ODD_FIELD
));
805 /* jump to end of even field if appropriate */
806 /* this points to (interlace)? pos. C: pos. B */
807 jump
= (interlace
) ? virt_to_bus(c2
+ (nlines
+ 1) / 2 + 2):
808 virt_to_bus(c2
+ nlines
+ 2);
809 /* if odd field, skip over to odd field clipmasking */
810 tab_cmd_dbdma(c2
++, DBDMA_NOP
| BR_IFSET
, jump
);
812 /* even field mask: */
813 tab_cmd_store(c2
++, (unsigned)(&pb
->planb_base_phys
->ch2
.br_sel
),
814 PLANB_SET(DMA_ABORT
));
815 /* this points to pos. B */
816 jump
= (interlace
) ? virt_to_bus(c2
+ nlines
+ 1):
817 virt_to_bus(c2
+ nlines
);
818 base
= virt_to_bus(pb
->mask
);
819 for (i
=0; i
< nlines
; i
+= stepsize
, c2
++)
820 tab_cmd_gen(c2
, OUTPUT_MORE
| KEY_STREAM0
| BR_IFSET
, 96,
821 base
+ i
* 96, jump
);
823 /* For non-interlaced, we use only even fields */
825 goto cmd_tab_mask_end
;
827 /* odd field mask: */
828 /* C */ tab_cmd_store(c2
++, (unsigned)(&pb
->planb_base_phys
->ch2
.br_sel
),
829 PLANB_SET(DMA_ABORT
));
830 /* this points to pos. B */
831 jump
= virt_to_bus(c2
+ nlines
/ 2);
832 base
= virt_to_bus(pb
->mask
);
833 for (i
=1; i
< nlines
; i
+= 2, c2
++) /* abort if set */
834 tab_cmd_gen(c2
, OUTPUT_MORE
| KEY_STREAM0
| BR_IFSET
, 96,
835 base
+ i
* 96, jump
);
837 /* Inform channel 1 and jump back to start */
839 /* ok, I just realized this is kind of flawed. */
840 /* this part is reached only after odd field clipmasking. */
841 /* wanna clean up? */
842 /* wait for field sync to be set */
843 /* corresponds to fsync (1) of ch1 */
844 /* B */ tab_cmd_dbdma(c2
++, DBDMA_NOP
| WAIT_IFCLR
, 0);
845 /* restart ch1, meant to clear any dead bit or something */
846 tab_cmd_store(c2
++, (unsigned)(&pb
->planb_base_phys
->ch1
.control
),
848 tab_cmd_store(c2
++, (unsigned)(&pb
->planb_base_phys
->ch1
.control
),
850 pb
->overlay_last2
= c2
; /* keep a pointer to the last command */
851 /* start over even field clipmasking */
852 tab_cmd_dbdma(c2
, DBDMA_NOP
| BR_ALWAYS
, virt_to_bus(pb
->ch2_cmd
));
858 /*********************************/
859 /* grabdisplay support functions */
860 /*********************************/
862 static int palette2fmt
[] = {
880 #define PLANB_PALETTE_MAX 15
882 static inline int overlay_is_active(struct planb
*pb
)
884 unsigned int size
= pb
->tab_size
* sizeof(struct dbdma_cmd
);
885 unsigned int caddr
= (unsigned)in_le32(&pb
->planb_base
->ch1
.cmdptr
);
887 return (in_le32(&pb
->overlay_last1
->cmd_dep
) == pb
->ch1_cmd_phys
)
888 && (caddr
< (pb
->ch1_cmd_phys
+ size
))
889 && (caddr
>= (unsigned)pb
->ch1_cmd_phys
);
892 static int vgrab(struct planb
*pb
, struct video_mmap
*mp
)
894 unsigned int fr
= mp
->frame
;
897 if(pb
->rawbuf
==NULL
) {
899 if((err
=grabbuf_alloc(pb
)))
903 IDEBUG("PlanB: grab %d: %dx%d(%u)\n", pb
->grabbing
,
904 mp
->width
, mp
->height
, fr
);
906 if(pb
->grabbing
>= MAX_GBUFFERS
)
908 if(fr
> (MAX_GBUFFERS
- 1) || fr
< 0)
910 if(mp
->height
<= 0 || mp
->width
<= 0)
912 if(mp
->format
< 0 || mp
->format
>= PLANB_PALETTE_MAX
)
914 if((format
= palette2fmt
[mp
->format
]) == 0)
916 if (mp
->height
* mp
->width
* format
> PLANB_MAX_FBUF
) /* format = bpp */
920 if(mp
->width
!= pb
->gwidth
[fr
] || mp
->height
!= pb
->gheight
[fr
] ||
921 format
!= pb
->gfmt
[fr
] || (pb
->gnorm_switch
[fr
])) {
923 #ifndef PLANB_GSCANLINE
924 unsigned int osize
= pb
->gwidth
[fr
] * pb
->gheight
[fr
]
926 unsigned int nsize
= mp
->width
* mp
->height
* format
;
929 IDEBUG("PlanB: gwidth = %d, gheight = %d, mp->format = %u\n",
930 mp
->width
, mp
->height
, mp
->format
);
932 #ifndef PLANB_GSCANLINE
933 if(pb
->gnorm_switch
[fr
])
936 for(i
= pb
->gbuf_idx
[fr
]; osize
> 0; i
++) {
937 memset((void *)pb
->rawbuf
[i
], 0, PAGE_SIZE
);
941 for(i
= pb
->l_fr_addr_idx
[fr
]; i
< pb
->l_fr_addr_idx
[fr
]
943 memset((void *)pb
->rawbuf
[i
], 0, PAGE_SIZE
);
947 if(pb->gnorm_switch[fr])
948 memset((void *)pb->gbuffer[fr], 0,
949 pb->gbytes_per_line * pb->gheight[fr]);
952 for(i = 0; i < pb->gheight[fr]; i++) {
953 memset((void *)(pb->gbuffer[fr]
954 + pb->gbytes_per_line * i
959 pb
->gwidth
[fr
] = mp
->width
;
960 pb
->gheight
[fr
] = mp
->height
;
961 pb
->gfmt
[fr
] = format
;
962 pb
->last_cmd
[fr
] = setup_grab_cmd(fr
, pb
);
963 planb_pre_capture(fr
, pb
->gfmt
[fr
], pb
); /* gfmt = bpp */
964 pb
->need_pre_capture
[fr
] = 1;
965 pb
->gnorm_switch
[fr
] = 0;
967 pb
->need_pre_capture
[fr
] = 0;
968 pb
->frame_stat
[fr
] = GBUFFER_GRABBING
;
969 if(!(ACTIVE
& in_le32(&pb
->planb_base
->ch1
.status
))) {
971 IDEBUG("PlanB: ch1 inactive, initiating grabbing\n");
973 planb_dbdma_stop(&pb
->planb_base
->ch1
);
974 if(pb
->need_pre_capture
[fr
]) {
976 IDEBUG("PlanB: padding pre-capture sequence\n");
978 out_le32 (&pb
->planb_base
->ch1
.cmdptr
,
979 virt_to_bus(pb
->pre_cmd
[fr
]));
981 tab_cmd_dbdma(pb
->last_cmd
[fr
], DBDMA_STOP
, 0);
982 tab_cmd_dbdma(pb
->cap_cmd
[fr
], DBDMA_NOP
, 0);
983 /* let's be on the safe side. here is not timing critical. */
984 tab_cmd_dbdma((pb
->cap_cmd
[fr
] + 1), DBDMA_NOP
, 0);
985 out_le32 (&pb
->planb_base
->ch1
.cmdptr
,
986 virt_to_bus(pb
->cap_cmd
[fr
]));
988 planb_dbdma_restart(&pb
->planb_base
->ch1
);
993 IDEBUG("PlanB: ch1 active, grabbing being queued\n");
995 if((pb
->last_fr
== -1) || ((pb
->last_fr
== -2) &&
996 overlay_is_active(pb
))) {
998 IDEBUG("PlanB: overlay is active, grabbing defered\n");
1000 tab_cmd_dbdma(pb
->last_cmd
[fr
],
1001 DBDMA_NOP
| BR_ALWAYS
,
1002 virt_to_bus(pb
->ch1_cmd
));
1003 if(pb
->need_pre_capture
[fr
]) {
1005 IDEBUG("PlanB: padding pre-capture sequence\n");
1007 tab_cmd_store(pb
->pre_cmd
[fr
],
1008 virt_to_bus(&pb
->overlay_last1
->cmd_dep
),
1009 virt_to_bus(pb
->ch1_cmd
));
1011 out_le32 (&pb
->overlay_last1
->cmd_dep
,
1012 virt_to_bus(pb
->pre_cmd
[fr
]));
1014 tab_cmd_store(pb
->cap_cmd
[fr
],
1015 virt_to_bus(&pb
->overlay_last1
->cmd_dep
),
1016 virt_to_bus(pb
->ch1_cmd
));
1017 tab_cmd_dbdma((pb
->cap_cmd
[fr
] + 1),
1020 out_le32 (&pb
->overlay_last1
->cmd_dep
,
1021 virt_to_bus(pb
->cap_cmd
[fr
]));
1023 for(i
= 0; overlay_is_active(pb
) && i
< 999; i
++)
1024 IDEBUG("PlanB: waiting for overlay done\n");
1025 tab_cmd_dbdma(pb
->ch1_cmd
, DBDMA_NOP
, 0);
1026 pb
->prev_last_fr
= fr
;
1028 } else if(pb
->last_fr
== -2) {
1030 IDEBUG("PlanB: mixed mode detected, grabbing"
1031 " will be done before activating overlay\n");
1033 tab_cmd_dbdma(pb
->ch1_cmd
, DBDMA_NOP
, 0);
1034 if(pb
->need_pre_capture
[fr
]) {
1036 IDEBUG("PlanB: padding pre-capture sequence\n");
1038 tab_cmd_dbdma(pb
->last_cmd
[pb
->prev_last_fr
],
1039 DBDMA_NOP
| BR_ALWAYS
,
1040 virt_to_bus(pb
->pre_cmd
[fr
]));
1043 tab_cmd_dbdma(pb
->cap_cmd
[fr
], DBDMA_NOP
, 0);
1044 if(pb
->gwidth
[pb
->prev_last_fr
] !=
1046 || pb
->gheight
[pb
->prev_last_fr
] !=
1048 || pb
->gfmt
[pb
->prev_last_fr
] !=
1050 tab_cmd_dbdma((pb
->cap_cmd
[fr
] + 1),
1053 tab_cmd_dbdma((pb
->cap_cmd
[fr
] + 1),
1054 DBDMA_NOP
| BR_ALWAYS
,
1055 virt_to_bus(pb
->cap_cmd
[fr
] + 16));
1056 tab_cmd_dbdma(pb
->last_cmd
[pb
->prev_last_fr
],
1057 DBDMA_NOP
| BR_ALWAYS
,
1058 virt_to_bus(pb
->cap_cmd
[fr
]));
1061 tab_cmd_dbdma(pb
->last_cmd
[fr
],
1062 DBDMA_NOP
| BR_ALWAYS
,
1063 virt_to_bus(pb
->ch1_cmd
));
1065 pb
->prev_last_fr
= fr
;
1069 IDEBUG("PlanB: active grabbing session detected\n");
1071 if(pb
->need_pre_capture
[fr
]) {
1073 IDEBUG("PlanB: padding pre-capture sequence\n");
1075 tab_cmd_dbdma(pb
->last_cmd
[pb
->last_fr
],
1076 DBDMA_NOP
| BR_ALWAYS
,
1077 virt_to_bus(pb
->pre_cmd
[fr
]));
1080 tab_cmd_dbdma(pb
->last_cmd
[fr
], DBDMA_STOP
, 0);
1081 tab_cmd_dbdma(pb
->cap_cmd
[fr
], DBDMA_NOP
, 0);
1082 if(pb
->gwidth
[pb
->last_fr
] != pb
->gwidth
[fr
]
1083 || pb
->gheight
[pb
->last_fr
] !=
1085 || pb
->gfmt
[pb
->last_fr
] !=
1087 tab_cmd_dbdma((pb
->cap_cmd
[fr
] + 1),
1090 tab_cmd_dbdma((pb
->cap_cmd
[fr
] + 1),
1091 DBDMA_NOP
| BR_ALWAYS
,
1092 virt_to_bus(pb
->cap_cmd
[fr
] + 16));
1093 tab_cmd_dbdma(pb
->last_cmd
[pb
->last_fr
],
1094 DBDMA_NOP
| BR_ALWAYS
,
1095 virt_to_bus(pb
->cap_cmd
[fr
]));
1100 if(!(ACTIVE
& in_le32(&pb
->planb_base
->ch1
.status
))) {
1102 IDEBUG("PlanB: became inactive in the mean time..."
1105 planb_dbdma_stop(&pb
->planb_base
->ch1
);
1106 out_le32 (&pb
->planb_base
->ch1
.cmdptr
,
1107 virt_to_bus(pb
->cap_cmd
[fr
]));
1108 planb_dbdma_restart(&pb
->planb_base
->ch1
);
1117 static void planb_pre_capture(int fr
, int bpp
, struct planb
*pb
)
1119 volatile struct dbdma_cmd
*c1
= pb
->pre_cmd
[fr
];
1120 int interlace
= (pb
->gheight
[fr
] > pb
->maxlines
/2)? 1: 0;
1122 tab_cmd_dbdma(c1
++, DBDMA_NOP
, 0);
1123 if((c1
= cmd_geo_setup(c1
, pb
->gwidth
[fr
], pb
->gheight
[fr
], interlace
,
1124 bpp
, 0, pb
)) == NULL
) {
1125 printk(KERN_WARNING
"PlanB: encountered some problems\n");
1126 tab_cmd_dbdma(pb
->pre_cmd
[fr
] + 1, DBDMA_STOP
, 0);
1129 /* Sync to even field */
1130 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->ch1
.wait_sel
),
1131 PLANB_SET(FIELD_SYNC
));
1132 tab_cmd_dbdma(c1
++, DBDMA_NOP
| WAIT_IFCLR
, 0);
1133 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->ch1
.br_sel
),
1134 PLANB_SET(ODD_FIELD
));
1135 tab_cmd_dbdma(c1
++, DBDMA_NOP
| WAIT_IFSET
, 0);
1136 tab_cmd_dbdma(c1
, DBDMA_NOP
| BR_IFSET
, virt_to_bus(c1
-3)); c1
++;
1137 tab_cmd_dbdma(c1
++, DBDMA_NOP
| INTR_ALWAYS
, 0);
1138 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->ch1
.br_sel
),
1139 PLANB_SET(DMA_ABORT
));
1140 /* For non-interlaced, we use even fields only */
1141 if (pb
->gheight
[fr
] <= pb
->maxlines
/2)
1142 goto cmd_tab_data_end
;
1143 /* Sync to odd field */
1144 tab_cmd_dbdma(c1
++, DBDMA_NOP
| WAIT_IFCLR
, 0);
1145 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->ch1
.br_sel
),
1146 PLANB_SET(ODD_FIELD
));
1147 tab_cmd_dbdma(c1
++, DBDMA_NOP
| WAIT_IFSET
, 0);
1148 tab_cmd_dbdma(c1
, DBDMA_NOP
| BR_IFCLR
, virt_to_bus(c1
-3)); c1
++;
1149 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->ch1
.br_sel
),
1150 PLANB_SET(DMA_ABORT
));
1152 tab_cmd_dbdma(c1
, DBDMA_NOP
| BR_ALWAYS
, virt_to_bus(pb
->cap_cmd
[fr
]));
1157 static volatile struct dbdma_cmd
*setup_grab_cmd(int fr
, struct planb
*pb
)
1159 int i
, bpp
, count
, nlines
, stepsize
, interlace
;
1160 #ifdef PLANB_GSCANLINE
1163 int nlpp
, leftover1
;
1168 volatile struct dbdma_cmd
*c1
;
1169 volatile struct dbdma_cmd
*jump_addr
;
1171 c1
= pb
->cap_cmd
[fr
];
1172 interlace
= (pb
->gheight
[fr
] > pb
->maxlines
/2)? 1: 0;
1173 bpp
= pb
->gfmt
[fr
]; /* gfmt = bpp */
1174 count
= bpp
* pb
->gwidth
[fr
];
1175 nlines
= pb
->gheight
[fr
];
1176 #ifdef PLANB_GSCANLINE
1177 scanline
= pb
->gbytes_per_line
;
1179 pb
->lsize
[fr
] = count
;
1185 /* Preamble commands: */
1186 tab_cmd_dbdma(c1
++, DBDMA_NOP
, 0);
1187 tab_cmd_dbdma(c1
, DBDMA_NOP
| BR_ALWAYS
, virt_to_bus(c1
+ 16)); c1
++;
1188 if((c1
= cmd_geo_setup(c1
, pb
->gwidth
[fr
], pb
->gheight
[fr
], interlace
,
1189 bpp
, 0, pb
)) == NULL
) {
1190 printk(KERN_WARNING
"PlanB: encountered serious problems\n");
1191 tab_cmd_dbdma(pb
->cap_cmd
[fr
] + 1, DBDMA_STOP
, 0);
1192 return (pb
->cap_cmd
[fr
] + 2);
1194 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->ch1
.wait_sel
),
1195 PLANB_SET(FIELD_SYNC
));
1196 tab_cmd_dbdma(c1
++, DBDMA_NOP
| WAIT_IFCLR
, 0);
1197 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->ch1
.br_sel
),
1198 PLANB_SET(ODD_FIELD
));
1199 tab_cmd_dbdma(c1
++, DBDMA_NOP
| WAIT_IFSET
, 0);
1200 tab_cmd_dbdma(c1
, DBDMA_NOP
| BR_IFSET
, virt_to_bus(c1
-3)); c1
++;
1201 tab_cmd_dbdma(c1
++, DBDMA_NOP
| INTR_ALWAYS
, 0);
1202 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->ch1
.br_sel
),
1203 PLANB_SET(DMA_ABORT
));
1207 jump_addr
= c1
+ TAB_FACTOR
* (nlines
+ 1) / 2;
1210 jump_addr
= c1
+ TAB_FACTOR
* nlines
;
1212 jump
= virt_to_bus(jump_addr
);
1214 /* even field data: */
1216 pagei
= pb
->gbuf_idx
[fr
];
1217 #ifdef PLANB_GSCANLINE
1218 for (i
= 0; i
< nlines
; i
+= stepsize
) {
1219 tab_cmd_gen(c1
++, INPUT_MORE
| BR_IFSET
, count
,
1220 virt_to_bus(pb
->rawbuf
[pagei
1221 + i
* scanline
/ PAGE_SIZE
]), jump
);
1229 base
= virt_to_bus(pb
->rawbuf
[pagei
]);
1230 nlpp
= (PAGE_SIZE
- leftover1
) / count
/ stepsize
;
1231 for(j
= 0; j
< nlpp
&& i
< nlines
; j
++, i
+= stepsize
, c1
++)
1232 tab_cmd_gen(c1
, INPUT_MORE
| KEY_STREAM0
| BR_IFSET
,
1233 count
, base
+ count
* j
* stepsize
+ leftover1
, jump
);
1235 int lov0
= PAGE_SIZE
- count
* nlpp
* stepsize
- leftover1
;
1241 tab_cmd_gen(c1
++, INPUT_MORE
| BR_IFSET
, count
, base
1242 + count
* nlpp
* stepsize
+ leftover1
, jump
);
1244 pb
->l_to_addr
[fr
][pb
->lnum
[fr
]] = pb
->rawbuf
[pagei
]
1245 + count
* nlpp
* stepsize
+ leftover1
;
1246 pb
->l_to_next_idx
[fr
][pb
->lnum
[fr
]] = pagei
+ 1;
1247 pb
->l_to_next_size
[fr
][pb
->lnum
[fr
]] = count
- lov0
;
1248 tab_cmd_gen(c1
++, INPUT_MORE
| BR_IFSET
, count
,
1249 virt_to_bus(pb
->rawbuf
[pb
->l_fr_addr_idx
[fr
]
1250 + pb
->lnum
[fr
]]), jump
);
1251 if(++pb
->lnum
[fr
] > MAX_LNUM
)
1254 leftover1
= count
* stepsize
- lov0
;
1259 } while(i
< nlines
);
1260 tab_cmd_dbdma(c1
, DBDMA_NOP
| BR_ALWAYS
, jump
);
1262 #endif /* PLANB_GSCANLINE */
1264 /* For non-interlaced, we use even fields only */
1266 goto cmd_tab_data_end
;
1268 /* Sync to odd field */
1269 tab_cmd_dbdma(c1
++, DBDMA_NOP
| WAIT_IFCLR
, 0);
1270 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->ch1
.br_sel
),
1271 PLANB_SET(ODD_FIELD
));
1272 tab_cmd_dbdma(c1
++, DBDMA_NOP
| WAIT_IFSET
, 0);
1273 tab_cmd_dbdma(c1
, DBDMA_NOP
| BR_IFCLR
, virt_to_bus(c1
-3)); c1
++;
1274 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->ch1
.br_sel
),
1275 PLANB_SET(DMA_ABORT
));
1277 /* odd field data: */
1278 jump_addr
= c1
+ TAB_FACTOR
* nlines
/ 2;
1279 jump
= virt_to_bus(jump_addr
);
1280 #ifdef PLANB_GSCANLINE
1281 for (i
= 1; i
< nlines
; i
+= stepsize
) {
1282 tab_cmd_gen(c1
++, INPUT_MORE
| BR_IFSET
, count
,
1283 virt_to_bus(pb
->rawbuf
[pagei
1284 + i
* scanline
/ PAGE_SIZE
]), jump
);
1289 pagei
= pb
->gbuf_idx
[fr
];
1295 base
= virt_to_bus(pb
->rawbuf
[pagei
]);
1296 nlpp
= (PAGE_SIZE
- leftover1
) / count
/ stepsize
;
1297 if(leftover1
>= count
) {
1298 tab_cmd_gen(c1
++, INPUT_MORE
| KEY_STREAM0
| BR_IFSET
, count
,
1299 base
+ leftover1
- count
, jump
);
1302 for(j
= 0; j
< nlpp
&& i
< nlines
; j
++, i
+= stepsize
, c1
++)
1303 tab_cmd_gen(c1
, INPUT_MORE
| KEY_STREAM0
| BR_IFSET
, count
,
1304 base
+ count
* (j
* stepsize
+ 1) + leftover1
, jump
);
1306 int lov0
= PAGE_SIZE
- count
* nlpp
* stepsize
- leftover1
;
1312 pb
->l_to_addr
[fr
][pb
->lnum
[fr
]] = pb
->rawbuf
[pagei
]
1313 + count
* (nlpp
* stepsize
+ 1) + leftover1
;
1314 pb
->l_to_next_idx
[fr
][pb
->lnum
[fr
]] = pagei
+ 1;
1315 pb
->l_to_next_size
[fr
][pb
->lnum
[fr
]] = count
* stepsize
1317 tab_cmd_gen(c1
++, INPUT_MORE
| BR_IFSET
, count
,
1318 virt_to_bus(pb
->rawbuf
[pb
->l_fr_addr_idx
[fr
]
1319 + pb
->lnum
[fr
]]), jump
);
1320 if(++pb
->lnum
[fr
] > MAX_LNUM
)
1324 leftover1
= count
* stepsize
- lov0
;
1328 } while(i
< nlines
);
1330 tab_cmd_dbdma(c1
, DBDMA_NOP
| BR_ALWAYS
, jump
);
1332 #endif /* PLANB_GSCANLINE */
1335 tab_cmd_store(c1
++, (unsigned)(&pb
->planb_base_phys
->intr_stat
),
1336 (fr
<< 9) | PLANB_FRM_IRQ
| PLANB_GEN_IRQ
);
1338 tab_cmd_dbdma(c1
, DBDMA_STOP
, 0);
1344 static void planb_irq(int irq
, void *dev_id
, struct pt_regs
* regs
)
1346 unsigned int stat
, astat
;
1347 struct planb
*pb
= (struct planb
*)dev_id
;
1349 IDEBUG("PlanB: planb_irq()\n");
1351 /* get/clear interrupt status bits */
1353 stat
= in_le32(&pb
->planb_base
->intr_stat
);
1354 astat
= stat
& pb
->intr_mask
;
1355 out_le32(&pb
->planb_base
->intr_stat
, PLANB_FRM_IRQ
1356 & ~astat
& stat
& ~PLANB_GEN_IRQ
);
1357 IDEBUG("PlanB: stat = %X, astat = %X\n", stat
, astat
);
1359 if(astat
& PLANB_FRM_IRQ
) {
1360 unsigned int fr
= stat
>> 9;
1361 #ifndef PLANB_GSCANLINE
1364 IDEBUG("PlanB: PLANB_FRM_IRQ\n");
1368 IDEBUG("PlanB: grab %d: fr = %d, gcount = %d\n",
1369 pb
->grabbing
, fr
, pb
->gcount
);
1370 #ifndef PLANB_GSCANLINE
1371 IDEBUG("PlanB: %d * %d bytes are being copied over\n",
1372 pb
->lnum
[fr
], pb
->lsize
[fr
]);
1373 for(i
= 0; i
< pb
->lnum
[fr
]; i
++) {
1374 int first
= pb
->lsize
[fr
] - pb
->l_to_next_size
[fr
][i
];
1376 memcpy(pb
->l_to_addr
[fr
][i
],
1377 pb
->rawbuf
[pb
->l_fr_addr_idx
[fr
] + i
],
1379 memcpy(pb
->rawbuf
[pb
->l_to_next_idx
[fr
][i
]],
1380 pb
->rawbuf
[pb
->l_fr_addr_idx
[fr
] + i
] + first
,
1381 pb
->l_to_next_size
[fr
][i
]);
1384 pb
->frame_stat
[fr
] = GBUFFER_DONE
;
1386 wake_up_interruptible(&pb
->capq
);
1389 /* incorrect interrupts? */
1390 pb
->intr_mask
= PLANB_CLR_IRQ
;
1391 out_le32(&pb
->planb_base
->intr_stat
, PLANB_CLR_IRQ
);
1392 printk(KERN_ERR
"PlanB: IRQ lockup, cleared intrrupts"
1393 " unconditionally\n");
1396 /*******************************
1397 * Device Operations functions *
1398 *******************************/
1400 static int planb_open(struct video_device
*dev
, int mode
)
1402 struct planb
*pb
= (struct planb
*)dev
;
1404 if (pb
->user
== 0) {
1406 if((err
= planb_prepare_open(pb
)) != 0)
1411 DEBUG("PlanB: device opened\n");
1417 static void planb_close(struct video_device
*dev
)
1419 struct planb
*pb
= (struct planb
*)dev
;
1421 if(pb
->user
< 1) /* ??? */
1424 if (pb
->user
== 1) {
1426 planb_dbdma_stop(&pb
->planb_base
->ch2
);
1427 planb_dbdma_stop(&pb
->planb_base
->ch1
);
1430 planb_prepare_close(pb
);
1435 DEBUG("PlanB: device closed\n");
1440 static long planb_read(struct video_device
*v
, char *buf
, unsigned long count
,
1443 DEBUG("planb: read request\n");
1447 static long planb_write(struct video_device
*v
, const char *buf
,
1448 unsigned long count
, int nonblock
)
1450 DEBUG("planb: write request\n");
1454 static int planb_ioctl(struct video_device
*dev
, unsigned int cmd
, void *arg
)
1456 struct planb
*pb
=(struct planb
*)dev
;
1462 struct video_capability b
;
1464 DEBUG("PlanB: IOCTL VIDIOCGCAP\n");
1466 strcpy (b
.name
, pb
->video_dev
.name
);
1467 b
.type
= VID_TYPE_OVERLAY
| VID_TYPE_CLIPPING
|
1468 VID_TYPE_FRAMERAM
| VID_TYPE_SCALES
|
1470 b
.channels
= 2; /* composite & svhs */
1472 b
.maxwidth
= PLANB_MAXPIXELS
;
1473 b
.maxheight
= PLANB_MAXLINES
;
1474 b
.minwidth
= 32; /* wild guess */
1476 if (copy_to_user(arg
,&b
,sizeof(b
)))
1482 struct video_buffer v
;
1486 DEBUG("PlanB: IOCTL VIDIOCSFBUF\n");
1488 if (!capable(CAP_SYS_ADMIN
)
1489 || !capable(CAP_SYS_RAWIO
))
1491 if (copy_from_user(&v
, arg
,sizeof(v
)))
1502 fmt
= PLANB_COLOUR15
;
1507 fmt
= PLANB_COLOUR32
;
1513 if (bpp
* v
.width
> v
.bytesperline
) {
1518 pb
->win
.color_fmt
= fmt
;
1519 pb
->frame_buffer_phys
= (unsigned long) v
.base
;
1520 pb
->win
.sheight
= v
.height
;
1521 pb
->win
.swidth
= v
.width
;
1522 pb
->picture
.depth
= pb
->win
.depth
= v
.depth
;
1523 pb
->win
.bpl
= pb
->win
.bpp
* pb
->win
.swidth
;
1524 pb
->win
.pad
= v
.bytesperline
- pb
->win
.bpl
;
1526 DEBUG("PlanB: Display at %p is %d by %d, bytedepth %d,"
1527 " bpl %d (+ %d)\n", v
.base
, v
.width
,v
.height
,
1528 pb
->win
.bpp
, pb
->win
.bpl
, pb
->win
.pad
);
1530 pb
->cmd_buff_inited
= 0;
1532 suspend_overlay(pb
);
1541 struct video_buffer v
;
1543 DEBUG("PlanB: IOCTL VIDIOCGFBUF\n");
1545 v
.base
= (void *)pb
->frame_buffer_phys
;
1546 v
.height
= pb
->win
.sheight
;
1547 v
.width
= pb
->win
.swidth
;
1548 v
.depth
= pb
->win
.depth
;
1549 v
.bytesperline
= pb
->win
.bpl
+ pb
->win
.pad
;
1550 if (copy_to_user(arg
, &v
, sizeof(v
)))
1558 if(copy_from_user(&i
, arg
, sizeof(i
)))
1561 DEBUG("PlanB: IOCTL VIDIOCCAPTURE Stop\n");
1570 DEBUG("PlanB: IOCTL VIDIOCCAPTURE Start\n");
1572 if (pb
->frame_buffer_phys
== 0 ||
1573 pb
->win
.width
== 0 ||
1574 pb
->win
.height
== 0)
1580 if(!(pb
->cmd_buff_inited
))
1589 struct video_channel v
;
1591 DEBUG("PlanB: IOCTL VIDIOCGCHAN\n");
1593 if(copy_from_user(&v
, arg
,sizeof(v
)))
1597 v
.type
= VIDEO_TYPE_CAMERA
;
1598 v
.norm
= pb
->win
.norm
;
1602 strcpy(v
.name
,"Composite");
1605 strcpy(v
.name
,"SVHS");
1611 if(copy_to_user(arg
,&v
,sizeof(v
)))
1618 struct video_channel v
;
1620 DEBUG("PlanB: IOCTL VIDIOCSCHAN\n");
1622 if(copy_from_user(&v
, arg
, sizeof(v
)))
1625 if (v
.norm
!= pb
->win
.norm
) {
1630 case VIDEO_MODE_PAL
:
1631 case VIDEO_MODE_SECAM
:
1632 maxlines
= PLANB_MAXLINES
;
1634 case VIDEO_MODE_NTSC
:
1635 maxlines
= PLANB_NTSC_MAXLINES
;
1642 /* empty the grabbing queue */
1644 interruptible_sleep_on(&pb
->capq
);
1645 pb
->maxlines
= maxlines
;
1646 pb
->win
.norm
= v
.norm
;
1647 /* Stop overlay if running */
1648 suspend_overlay(pb
);
1649 for(i
= 0; i
< MAX_GBUFFERS
; i
++)
1650 pb
->gnorm_switch
[i
] = 1;
1651 /* I know it's an overkill, but.... */
1653 /* ok, now init it accordingly */
1655 /* restart overlay if it was running */
1662 case 0: /* Composite */
1663 saa_set (SAA7196_IOCC
,
1664 ((saa_regs
[pb
->win
.norm
][SAA7196_IOCC
] &
1668 saa_set (SAA7196_IOCC
,
1669 ((saa_regs
[pb
->win
.norm
][SAA7196_IOCC
] &
1681 struct video_picture vp
= pb
->picture
;
1683 DEBUG("PlanB: IOCTL VIDIOCGPICT\n");
1685 switch(pb
->win
.color_fmt
) {
1687 vp
.palette
= VIDEO_PALETTE_GREY
;
1688 case PLANB_COLOUR15
:
1689 vp
.palette
= VIDEO_PALETTE_RGB555
;
1691 case PLANB_COLOUR32
:
1692 vp
.palette
= VIDEO_PALETTE_RGB32
;
1699 if(copy_to_user(arg
,&vp
,sizeof(vp
)))
1705 struct video_picture vp
;
1707 DEBUG("PlanB: IOCTL VIDIOCSPICT\n");
1709 if(copy_from_user(&vp
,arg
,sizeof(vp
)))
1712 /* Should we do sanity checks here? */
1713 saa_set (SAA7196_BRIG
, (unsigned char)
1714 ((pb
->picture
.brightness
) >> 8), pb
);
1715 saa_set (SAA7196_HUEC
, (unsigned char)
1716 ((pb
->picture
.hue
) >> 8) ^ 0x80, pb
);
1717 saa_set (SAA7196_CSAT
, (unsigned char)
1718 ((pb
->picture
.colour
) >> 9), pb
);
1719 saa_set (SAA7196_CONT
, (unsigned char)
1720 ((pb
->picture
.contrast
) >> 9), pb
);
1726 struct video_window vw
;
1727 struct video_clip clip
;
1730 DEBUG("PlanB: IOCTL VIDIOCSWIN\n");
1732 if(copy_from_user(&vw
,arg
,sizeof(vw
)))
1736 /* Stop overlay if running */
1737 suspend_overlay(pb
);
1738 pb
->win
.interlace
= (vw
.height
> pb
->maxlines
/2)? 1: 0;
1739 if (pb
->win
.x
!= vw
.x
||
1740 pb
->win
.y
!= vw
.y
||
1741 pb
->win
.width
!= vw
.width
||
1742 pb
->win
.height
!= vw
.height
||
1743 !pb
->cmd_buff_inited
) {
1746 pb
->win
.width
= vw
.width
;
1747 pb
->win
.height
= vw
.height
;
1750 /* Reset clip mask */
1751 memset ((void *) pb
->mask
, 0xff, (pb
->maxlines
1752 * ((PLANB_MAXPIXELS
+ 7) & ~7)) / 8);
1753 /* Add any clip rects */
1754 for (i
= 0; i
< vw
.clipcount
; i
++) {
1755 if (copy_from_user(&clip
, vw
.clips
+ i
,
1756 sizeof(struct video_clip
)))
1758 add_clip(pb
, &clip
);
1760 /* restart overlay if it was running */
1767 struct video_window vw
;
1769 DEBUG("PlanB: IOCTL VIDIOCGWIN\n");
1773 vw
.width
=pb
->win
.width
;
1774 vw
.height
=pb
->win
.height
;
1777 if(pb
->win
.interlace
)
1778 vw
.flags
|=VIDEO_WINDOW_INTERLACE
;
1779 if(copy_to_user(arg
,&vw
,sizeof(vw
)))
1786 IDEBUG("PlanB: IOCTL VIDIOCSYNC\n");
1788 if(copy_from_user((void *)&i
,arg
,sizeof(int)))
1791 IDEBUG("PlanB: sync to frame %d\n", i
);
1793 if(i
> (MAX_GBUFFERS
- 1) || i
< 0)
1796 switch (pb
->frame_stat
[i
]) {
1797 case GBUFFER_UNUSED
:
1799 case GBUFFER_GRABBING
:
1800 IDEBUG("PlanB: waiting for grab"
1802 interruptible_sleep_on(&pb
->capq
);
1803 if(signal_pending(current
))
1807 pb
->frame_stat
[i
] = GBUFFER_UNUSED
;
1813 case VIDIOCMCAPTURE
:
1815 struct video_mmap vm
;
1816 volatile unsigned int status
;
1818 IDEBUG("PlanB: IOCTL VIDIOCMCAPTURE\n");
1820 if(copy_from_user((void *) &vm
,(void *)arg
,sizeof(vm
)))
1822 status
= pb
->frame_stat
[vm
.frame
];
1823 if (status
!= GBUFFER_UNUSED
)
1826 return vgrab(pb
, &vm
);
1832 struct video_mbuf vm
;
1834 DEBUG("PlanB: IOCTL VIDIOCGMBUF\n");
1836 memset(&vm
, 0 , sizeof(vm
));
1837 vm
.size
= PLANB_MAX_FBUF
* MAX_GBUFFERS
;
1838 vm
.frames
= MAX_GBUFFERS
;
1839 for(i
= 0; i
<MAX_GBUFFERS
; i
++)
1840 vm
.offsets
[i
] = PLANB_MAX_FBUF
* i
;
1841 if(copy_to_user((void *)arg
, (void *)&vm
, sizeof(vm
)))
1846 case PLANBIOCGSAAREGS
:
1848 struct planb_saa_regs preg
;
1850 DEBUG("PlanB: IOCTL PLANBIOCGSAAREGS\n");
1852 if(copy_from_user(&preg
, arg
, sizeof(preg
)))
1854 if(preg
.addr
>= SAA7196_NUMREGS
)
1856 preg
.val
= saa_regs
[pb
->win
.norm
][preg
.addr
];
1857 if(copy_to_user((void *)arg
, (void *)&preg
,
1863 case PLANBIOCSSAAREGS
:
1865 struct planb_saa_regs preg
;
1867 DEBUG("PlanB: IOCTL PLANBIOCSSAAREGS\n");
1869 if(copy_from_user(&preg
, arg
, sizeof(preg
)))
1871 if(preg
.addr
>= SAA7196_NUMREGS
)
1873 saa_set (preg
.addr
, preg
.val
, pb
);
1879 struct planb_stat_regs pstat
;
1881 DEBUG("PlanB: IOCTL PLANBIOCGSTAT\n");
1883 pstat
.ch1_stat
= in_le32(&pb
->planb_base
->ch1
.status
);
1884 pstat
.ch2_stat
= in_le32(&pb
->planb_base
->ch2
.status
);
1885 pstat
.saa_stat0
= saa_status(0, pb
);
1886 pstat
.saa_stat1
= saa_status(1, pb
);
1888 if(copy_to_user((void *)arg
, (void *)&pstat
,
1894 case PLANBIOCSMODE
: {
1897 DEBUG("PlanB: IOCTL PLANBIOCSMODE\n");
1899 if(copy_from_user(&v
, arg
, sizeof(v
)))
1905 saa_set (SAA7196_STDC
,
1906 (saa_regs
[pb
->win
.norm
][SAA7196_STDC
] &
1909 case PLANB_VTR_MODE
:
1910 saa_set (SAA7196_STDC
,
1911 (saa_regs
[pb
->win
.norm
][SAA7196_STDC
] |
1921 case PLANBIOCGMODE
: {
1924 DEBUG("PlanB: IOCTL PLANBIOCGMODE\n");
1926 if(copy_to_user(arg
,&v
,sizeof(v
)))
1930 #ifdef PLANB_GSCANLINE
1931 case PLANBG_GRAB_BPL
: {
1932 int v
=pb
->gbytes_per_line
;
1934 DEBUG("PlanB: IOCTL PLANBG_GRAB_BPL\n");
1936 if(copy_to_user(arg
,&v
,sizeof(v
)))
1940 #endif /* PLANB_GSCANLINE */
1941 case PLANB_INTR_DEBUG
: {
1944 DEBUG("PlanB: IOCTL PLANB_INTR_DEBUG\n");
1946 if(copy_from_user(&i
, arg
, sizeof(i
)))
1949 /* avoid hang ups all together */
1950 for (i
= 0; i
< MAX_GBUFFERS
; i
++) {
1951 if(pb
->frame_stat
[i
] == GBUFFER_GRABBING
) {
1952 pb
->frame_stat
[i
] = GBUFFER_DONE
;
1957 wake_up_interruptible(&pb
->capq
);
1960 case PLANB_INV_REGS
: {
1962 struct planb_any_regs any
;
1964 DEBUG("PlanB: IOCTL PLANB_INV_REGS\n");
1966 if(copy_from_user(&any
, arg
, sizeof(any
)))
1968 if(any
.offset
< 0 || any
.offset
+ any
.bytes
> 0x400)
1972 for (i
= 0; i
< any
.bytes
; i
++) {
1974 in_8((unsigned char *)pb
->planb_base
1977 if(copy_to_user(arg
,&any
,sizeof(any
)))
1983 DEBUG("PlanB: Unimplemented IOCTL\n");
1984 return -ENOIOCTLCMD
;
1986 /* Some IOCTLs are currently unsupported on PlanB */
1987 case VIDIOCGTUNER
: {
1988 DEBUG("PlanB: IOCTL VIDIOCGTUNER\n");
1989 goto unimplemented
; }
1990 case VIDIOCSTUNER
: {
1991 DEBUG("PlanB: IOCTL VIDIOCSTUNER\n");
1992 goto unimplemented
; }
1994 DEBUG("PlanB: IOCTL VIDIOCSFREQ\n");
1995 goto unimplemented
; }
1997 DEBUG("PlanB: IOCTL VIDIOCGFREQ\n");
1998 goto unimplemented
; }
2000 DEBUG("PlanB: IOCTL VIDIOCKEY\n");
2001 goto unimplemented
; }
2002 case VIDIOCSAUDIO
: {
2003 DEBUG("PlanB: IOCTL VIDIOCSAUDIO\n");
2004 goto unimplemented
; }
2005 case VIDIOCGAUDIO
: {
2006 DEBUG("PlanB: IOCTL VIDIOCGAUDIO\n");
2007 goto unimplemented
; }
2009 DEBUG(" Unimplemented\n");
2010 return -ENOIOCTLCMD
;
2015 static int planb_mmap(struct video_device
*dev
, const char *adr
, unsigned long size
)
2018 struct planb
*pb
= (struct planb
*)dev
;
2019 unsigned long start
= (unsigned long)adr
;
2021 if (size
> MAX_GBUFFERS
* PLANB_MAX_FBUF
)
2025 if((err
=grabbuf_alloc(pb
)))
2028 for (i
= 0; i
< pb
->rawbuf_size
; i
++) {
2029 if (remap_page_range(start
, virt_to_phys((void *)pb
->rawbuf
[i
]),
2030 PAGE_SIZE
, PAGE_SHARED
))
2033 if (size
<= PAGE_SIZE
)
2040 /* This gets called upon device registration */
2041 /* we could do some init here */
2042 static int planb_init_done(struct video_device
*dev
)
2047 static struct video_device planb_template
=
2056 #if LINUX_VERSION_CODE >= 0x020100
2060 planb_mmap
, /* mmap? */
2062 NULL
, /* pointer to private data */
2067 static int init_planb(struct planb
*pb
)
2069 unsigned char saa_rev
;
2071 unsigned long flags
;
2073 memset ((void *) &pb
->win
, 0, sizeof (struct planb_window
));
2074 /* Simple sanity check */
2075 if(def_norm
>= NUM_SUPPORTED_NORM
|| def_norm
< 0) {
2076 printk(KERN_ERR
"PlanB: Option(s) invalid\n");
2079 pb
->win
.norm
= def_norm
;
2080 pb
->win
.mode
= PLANB_TV_MODE
; /* TV mode */
2081 pb
->win
.interlace
=1;
2084 pb
->win
.width
=768; /* 640 */
2085 pb
->win
.height
=576; /* 480 */
2088 btv
->win
.cropwidth
=768; /* 640 */
2089 btv
->win
.cropheight
=576; /* 480 */
2096 pb
->win
.color_fmt
=PLANB_COLOUR32
;
2097 pb
->win
.bpl
=1024*pb
->win
.bpp
;
2098 pb
->win
.swidth
=1024;
2099 pb
->win
.sheight
=768;
2100 #ifdef PLANB_GSCANLINE
2101 if((pb
->gbytes_per_line
= PLANB_MAXPIXELS
* 4) > PAGE_SIZE
2102 || (pb
->gbytes_per_line
<= 0))
2105 /* page align pb->gbytes_per_line for DMA purpose */
2106 for(i
= PAGE_SIZE
; pb
->gbytes_per_line
< (i
>>1);)
2108 pb
->gbytes_per_line
= i
;
2111 pb
->tab_size
= PLANB_MAXLINES
+ 40;
2114 init_waitqueue_head(&pb
->lockq
);
2122 init_waitqueue_head(&pb
->suspendq
);
2123 pb
->cmd_buff_inited
= 0;
2124 pb
->frame_buffer_phys
= 0;
2126 /* Reset DMA controllers */
2127 planb_dbdma_stop(&pb
->planb_base
->ch2
);
2128 planb_dbdma_stop(&pb
->planb_base
->ch1
);
2130 saa_rev
= (saa_status(0, pb
) & 0xf0) >> 4;
2131 printk(KERN_INFO
"PlanB: SAA7196 video processor rev. %d\n", saa_rev
);
2132 /* Initialize the SAA registers in memory and on chip */
2135 /* clear interrupt mask */
2136 pb
->intr_mask
= PLANB_CLR_IRQ
;
2138 save_flags(flags
); cli();
2139 result
= request_irq(pb
->irq
, planb_irq
, 0, "PlanB", (void *)pb
);
2141 if (result
==-EINVAL
)
2142 printk(KERN_ERR
"PlanB: Bad irq number (%d) "
2143 "or handler\n", (int)pb
->irq
);
2144 else if (result
==-EBUSY
)
2145 printk(KERN_ERR
"PlanB: I don't know why, "
2146 "but IRQ %d is busy\n", (int)pb
->irq
);
2147 restore_flags(flags
);
2150 disable_irq(pb
->irq
);
2151 restore_flags(flags
);
2153 /* Now add the template and register the device unit. */
2154 memcpy(&pb
->video_dev
,&planb_template
,sizeof(planb_template
));
2156 pb
->picture
.brightness
=0x90<<8;
2157 pb
->picture
.contrast
= 0x70 << 8;
2158 pb
->picture
.colour
= 0x70<<8;
2159 pb
->picture
.hue
= 0x8000;
2160 pb
->picture
.whiteness
= 0;
2161 pb
->picture
.depth
= pb
->win
.depth
;
2163 pb
->frame_stat
=NULL
;
2164 init_waitqueue_head(&pb
->capq
);
2165 for(i
=0; i
<MAX_GBUFFERS
; i
++) {
2166 pb
->gbuf_idx
[i
] = PLANB_MAX_FBUF
* i
/ PAGE_SIZE
;
2170 pb
->cap_cmd
[i
]=NULL
;
2171 #ifndef PLANB_GSCANLINE
2172 pb
->l_fr_addr_idx
[i
] = MAX_GBUFFERS
* (PLANB_MAX_FBUF
2173 / PAGE_SIZE
+ 1) + MAX_LNUM
* i
;
2181 /* enable interrupts */
2182 out_le32(&pb
->planb_base
->intr_stat
, PLANB_CLR_IRQ
);
2183 pb
->intr_mask
= PLANB_FRM_IRQ
;
2184 enable_irq(pb
->irq
);
2186 if(video_register_device(&pb
->video_dev
, VFL_TYPE_GRABBER
)<0)
2193 * Scan for a PlanB controller, request the irq and map the io memory
2196 static int find_planb(void)
2199 struct device_node
*planb_devices
;
2200 unsigned char dev_fn
, confreg
, bus
;
2201 unsigned int old_base
, new_base
;
2203 struct pci_dev
*pdev
;
2205 if (_machine
!= _MACH_Pmac
)
2208 planb_devices
= find_devices("planb");
2209 if (planb_devices
== 0) {
2211 printk(KERN_WARNING
"PlanB: no device found!\n");
2215 if (planb_devices
->next
!= NULL
)
2216 printk(KERN_ERR
"Warning: only using first PlanB device!\n");
2220 if (planb_devices
->n_addrs
!= 1) {
2221 printk (KERN_WARNING
"PlanB: expecting 1 address for planb "
2222 "(got %d)", planb_devices
->n_addrs
);
2226 if (planb_devices
->n_intrs
== 0) {
2227 printk(KERN_WARNING
"PlanB: no intrs for device %s\n",
2228 planb_devices
->full_name
);
2231 irq
= planb_devices
->intrs
[0].line
;
2234 /* Initialize PlanB's PCI registers */
2236 /* There is a bug with the way OF assigns addresses
2237 to the devices behind the chaos bridge.
2238 control needs only 0x1000 of space, but decodes only
2239 the upper 16 bits. It therefore occupies a full 64K.
2240 OF assigns the planb controller memory within this space;
2241 so we need to change that here in order to access planb. */
2243 /* We remap to 0xf1000000 in hope that nobody uses it ! */
2245 bus
= (planb_devices
->addrs
[0].space
>> 16) & 0xff;
2246 dev_fn
= (planb_devices
->addrs
[0].space
>> 8) & 0xff;
2247 confreg
= planb_devices
->addrs
[0].space
& 0xff;
2248 old_base
= planb_devices
->addrs
[0].address
;
2249 new_base
= 0xf1000000;
2251 DEBUG("PlanB: Found on bus %d, dev %d, func %d, "
2252 "membase 0x%x (base reg. 0x%x)\n",
2253 bus
, PCI_SLOT(dev_fn
), PCI_FUNC(dev_fn
), old_base
, confreg
);
2255 pdev
= pci_find_slot (bus
, dev_fn
);
2257 printk(KERN_ERR
"cannot find slot\n");
2258 /* XXX handle error */
2261 /* Enable response in memory space, bus mastering,
2262 use memory write and invalidate */
2263 pci_write_config_word (pdev
, PCI_COMMAND
,
2264 PCI_COMMAND_MEMORY
| PCI_COMMAND_MASTER
|
2265 PCI_COMMAND_INVALIDATE
);
2266 /* Set PCI Cache line size & latency timer */
2267 pci_write_config_byte (pdev
, PCI_CACHE_LINE_SIZE
, 0x8);
2268 pci_write_config_byte (pdev
, PCI_LATENCY_TIMER
, 0x40);
2270 /* Set the new base address */
2271 pci_write_config_dword (pdev
, confreg
, new_base
);
2273 planb_regs
= (volatile struct planb_registers
*)
2274 ioremap (new_base
, 0x400);
2275 pb
->planb_base
= planb_regs
;
2276 pb
->planb_base_phys
= (struct planb_registers
*)new_base
;
2282 static void release_planb(void)
2287 for (i
=0;i
<planb_num
; i
++)
2291 /* stop and flash DMAs unconditionally */
2292 planb_dbdma_stop(&pb
->planb_base
->ch2
);
2293 planb_dbdma_stop(&pb
->planb_base
->ch1
);
2295 /* clear and free interrupts */
2296 pb
->intr_mask
= PLANB_CLR_IRQ
;
2297 out_le32 (&pb
->planb_base
->intr_stat
, PLANB_CLR_IRQ
);
2298 free_irq(pb
->irq
, pb
);
2300 /* make sure all allocated memory are freed */
2301 planb_prepare_close(pb
);
2303 printk(KERN_INFO
"PlanB: unregistering with v4l\n");
2304 video_unregister_device(&pb
->video_dev
);
2306 /* note that iounmap() does nothing on the PPC right now */
2307 iounmap ((void *)pb
->planb_base
);
2313 int init_module(void)
2316 int __init
init_planbs(struct video_init
*unused
)
2321 if (find_planb()<=0)
2324 for (i
=0; i
<planb_num
; i
++) {
2325 if (init_planb(&planbs
[i
])<0) {
2326 printk(KERN_ERR
"PlanB: error registering device %d"
2331 printk(KERN_INFO
"PlanB: registered device %d with v4l\n", i
);
2338 void cleanup_module(void)