Portability cleanup as required by Linus.
[linux-2.6/linux-mips.git] / drivers / char / planb.c
blobfe5f905e9ab9990dd22d2e8937be7e6e80de0393
1 /*
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>
41 #include <linux/mm.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>
47 #include <asm/io.h>
48 #include <asm/prom.h>
49 #include <asm/dbdma.h>
50 #include <asm/pgtable.h>
51 #include <asm/page.h>
52 #include <asm/irq.h>
54 #include "planb.h"
55 #include "saa7196.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? */
65 #define PLANB_MAX 1
67 static int planb_num;
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,
104 unsigned int);
105 static inline void tab_cmd_store(volatile struct dbdma_cmd *, unsigned int,
106 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)
124 int i, npage;
126 npage = MAX_GBUFFERS * ((PLANB_MAX_FBUF / PAGE_SIZE + 1)
127 #ifndef PLANB_GSCANLINE
128 + MAX_LNUM
129 #endif /* PLANB_GSCANLINE */
131 if ((pb->rawbuf = (unsigned char**) kmalloc (npage
132 * sizeof(unsigned long), GFP_KERNEL)) == 0)
133 return -ENOMEM;
134 for (i = 0; i < npage; i++) {
135 pb->rawbuf[i] = (unsigned char *)__get_free_pages(GFP_KERNEL
136 |GFP_DMA, 0);
137 if (!pb->rawbuf[i])
138 break;
139 set_bit(PG_reserved, &mem_map[MAP_NR(pb->rawbuf[i])].flags);
141 if (i-- < npage) {
142 printk(KERN_DEBUG "PlanB: init_grab: grab buffer not allocated\n");
143 for (; i > 0; i--) {
144 clear_bit(PG_reserved,
145 &mem_map[MAP_NR(pb->rawbuf[i])].flags);
146 free_pages((unsigned long)pb->rawbuf[i], 0);
148 kfree(pb->rawbuf);
149 return -ENOBUFS;
151 pb->rawbuf_size = npage;
152 return 0;
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();
163 return;
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);
177 #else
178 current->timeout = jiffies + 30 * HZ / 1000; /* 30 ms */;
179 schedule();
180 #endif
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);
191 return;
194 static void saa_init_regs(struct planb *pb)
196 int i;
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,
203 struct planb *pb)
205 int ht, norm = pb->win.norm;
207 switch(bpp) {
208 case 2:
209 /* RGB555+a 1x16-bit + 16-bit transparent */
210 saa_regs[norm][SAA7196_FMTS] &= ~0x3;
211 break;
212 case 1:
213 case 4:
214 /* RGB888 1x24-bit + 8-bit transparent */
215 saa_regs[norm][SAA7196_FMTS] &= ~0x1;
216 saa_regs[norm][SAA7196_FMTS] |= 0x2;
217 break;
218 default:
219 return -EINVAL;
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)
227 | (ht >> 8 & 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;
235 return 0;
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)
250 int i = 0;
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");
255 i++;
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),
294 SAA7196_FMTS);
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),
298 SAA7196_DPATH);
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),
306 SAA7196_OUTPIX);
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),
310 SAA7196_HFILT);
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),
314 SAA7196_OUTLINE);
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),
318 SAA7196_VYP);
319 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),
320 saa_regs[norm][SAA7196_VYP]);
321 return c1;
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);
333 repeat:
334 set_current_state(TASK_UNINTERRUPTIBLE);
335 if (pb->lock) {
336 schedule();
337 goto repeat;
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");
346 if(pb->lock)
347 __planb_wait(pb);
350 static inline void planb_lock(struct planb *pb)
352 DEBUG("PlanB: planb_lock\n");
353 if(pb->lock)
354 __planb_wait(pb);
355 pb->lock = 1;
358 static inline void planb_unlock(struct planb *pb)
360 DEBUG("PlanB: planb_unlock\n");
361 pb->lock = 0;
362 wake_up(&pb->lockq);
365 /***************/
366 /* Driver Core */
367 /***************/
369 static int planb_prepare_open(struct planb *pb)
371 int i, size;
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)
381 return -ENOMEM;
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]
394 + PLANB_DUMMY);
395 pb->mask = (unsigned char *)(pb->frame_stat+MAX_GBUFFERS);
397 pb->rawbuf = NULL;
398 pb->rawbuf_size = 0;
399 pb->grabbing = 0;
400 for (i = 0; i < MAX_GBUFFERS; i++) {
401 pb->frame_stat[i] = GBUFFER_UNUSED;
402 pb->gwidth[i] = 0;
403 pb->gheight[i] = 0;
404 pb->gfmt[i] = 0;
405 pb->gnorm_switch[i] = 0;
406 #ifndef PLANB_GSCANLINE
407 pb->lsize[i] = 0;
408 pb->lnum[i] = 0;
409 #endif /* PLANB_GSCANLINE */
411 pb->gcount = 0;
412 pb->suspend = 0;
413 pb->last_fr = -999;
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);
420 return 0;
423 static void planb_prepare_close(struct planb *pb)
425 int i;
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);
433 pb->priv_space = 0;
434 pb->cmd_buff_inited = 0;
436 if(pb->rawbuf) {
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);
442 kfree(pb->rawbuf);
444 pb->rawbuf = NULL;
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));
468 eieio();
469 pb->prev_last_fr = pb->last_fr;
470 pb->last_fr = -2;
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);
479 } else {
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);
492 pb->last_fr = -1;
494 return;
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);
507 pb->last_fr = -999;
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);
511 eieio();
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;
528 return;
531 static void suspend_overlay(struct planb *pb)
533 int fr = -1;
534 struct dbdma_cmd last;
536 DEBUG("PlanB: suspend_overlay: %d\n", pb->suspend);
538 if(pb->suspend++)
539 return;
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));
552 return;
555 pb->suspended.overlay = 0;
556 pb->suspended.frame = fr;
557 memcpy(&pb->suspended.cmd, &last, sizeof(last));
558 return;
561 static void resume_overlay(struct planb *pb)
564 DEBUG("PlanB: resume_overlay: %d\n", pb->suspend);
566 if(pb->suspend > 1)
567 return;
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)) {
573 goto finish;
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));
598 finish:
599 pb->suspend--;
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);
613 if(xc < 0) {
614 wc += xc;
615 xc = 0;
617 if(yc < 0) {
618 hc += yc;
619 yc = 0;
621 if(xc + wc > ww)
622 wc = ww - xc;
623 if(wc <= 0) /* Nothing to do */
624 return;
625 if(yc + hc > hw)
626 hc = hw - yc;
628 for (y = yc; y < yc+hc; y++) {
629 xtmp1=xc>>3;
630 xtmp2=(xc+wc)>>3;
631 base = pb->mask + y*96;
632 if(xc != 0 || wc >= 8)
633 *(base + xtmp1) &= (unsigned char)(0x00ff &
634 (0xff00 >> (xc&7)));
635 for (x = xtmp1 + 1; x < xtmp2; x++) {
636 *(base + x) = 0;
638 if(xc < (ww & ~0x7))
639 *(base + xtmp2) &= (unsigned char)(0x00ff >>
640 ((xc+wc) & 7));
643 return;
646 static void fill_cmd_buff(struct planb *pb)
648 int restore = 0;
649 volatile struct dbdma_cmd last;
651 DEBUG("PlanB: fill_cmd_buff()\n");
653 if(pb->overlay_last1 != pb->ch1_cmd) {
654 restore = 1;
655 last = *(pb->overlay_last1);
657 memset ((void *) pb->ch1_cmd, 0, 2 * pb->tab_size
658 * sizeof(struct dbdma_cmd));
659 cmd_buff (pb);
660 if(restore)
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) {
665 int i;
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]))
672 goto found;
673 } else {
674 if(jump_addr == virt_to_bus(pb->cap_cmd[i]))
675 goto found;
679 DEBUG("PlanB: not found...\n");
681 goto out;
682 found:
683 if(pb->need_pre_capture[i])
684 out_le32(&pb->pre_cmd[i]->phy_addr,
685 virt_to_bus(pb->overlay_last1));
686 else
687 out_le32(&pb->cap_cmd[i]->phy_addr,
688 virt_to_bus(pb->overlay_last1));
691 out:
692 pb->cmd_buff_inited = 1;
694 return;
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;
705 bpp = pb->win.bpp;
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);
711 /* Do video in: */
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);
723 return;
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),
739 PLANB_SET(CH_SYNC));
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);
746 if (interlace) {
747 stepsize = 2;
748 jump = virt_to_bus(c1 + (nlines + 1) / 2);
749 } else {
750 stepsize = 1;
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 */
760 if (!interlace)
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),
774 PLANB_SET(CH_SYNC));
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 */
785 cmd_tab_data_end:
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),
794 PLANB_SET(CH_SYNC));
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),
799 PLANB_CLR(CH_SYNC));
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 */
824 if(!interlace)
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 */
838 cmd_tab_mask_end:
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),
847 PLANB_CLR(RUN));
848 tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch1.control),
849 PLANB_SET(RUN));
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));
854 eieio();
855 return;
858 /*********************************/
859 /* grabdisplay support functions */
860 /*********************************/
862 static int palette2fmt[] = {
864 PLANB_GRAY,
868 PLANB_COLOUR32,
869 PLANB_COLOUR15,
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;
895 unsigned int format;
897 if(pb->rawbuf==NULL) {
898 int err;
899 if((err=grabbuf_alloc(pb)))
900 return err;
903 IDEBUG("PlanB: grab %d: %dx%d(%u)\n", pb->grabbing,
904 mp->width, mp->height, fr);
906 if(pb->grabbing >= MAX_GBUFFERS)
907 return -ENOBUFS;
908 if(fr > (MAX_GBUFFERS - 1) || fr < 0)
909 return -EINVAL;
910 if(mp->height <= 0 || mp->width <= 0)
911 return -EINVAL;
912 if(mp->format < 0 || mp->format >= PLANB_PALETTE_MAX)
913 return -EINVAL;
914 if((format = palette2fmt[mp->format]) == 0)
915 return -EINVAL;
916 if (mp->height * mp->width * format > PLANB_MAX_FBUF) /* format = bpp */
917 return -EINVAL;
919 planb_lock(pb);
920 if(mp->width != pb->gwidth[fr] || mp->height != pb->gheight[fr] ||
921 format != pb->gfmt[fr] || (pb->gnorm_switch[fr])) {
922 int i;
923 #ifndef PLANB_GSCANLINE
924 unsigned int osize = pb->gwidth[fr] * pb->gheight[fr]
925 * pb->gfmt[fr];
926 unsigned int nsize = mp->width * mp->height * format;
927 #endif
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])
934 nsize = 0;
935 if (nsize < osize) {
936 for(i = pb->gbuf_idx[fr]; osize > 0; i++) {
937 memset((void *)pb->rawbuf[i], 0, PAGE_SIZE);
938 osize -= PAGE_SIZE;
941 for(i = pb->l_fr_addr_idx[fr]; i < pb->l_fr_addr_idx[fr]
942 + pb->lnum[fr]; i++)
943 memset((void *)pb->rawbuf[i], 0, PAGE_SIZE);
944 #else
945 /* XXX TODO */
947 if(pb->gnorm_switch[fr])
948 memset((void *)pb->gbuffer[fr], 0,
949 pb->gbytes_per_line * pb->gheight[fr]);
950 else {
951 if(mp->
952 for(i = 0; i < pb->gheight[fr]; i++) {
953 memset((void *)(pb->gbuffer[fr]
954 + pb->gbytes_per_line * i
958 #endif
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;
966 } else
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]));
980 } else {
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);
989 pb->last_fr = fr;
990 } else {
991 int i;
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));
1010 eieio();
1011 out_le32 (&pb->overlay_last1->cmd_dep,
1012 virt_to_bus(pb->pre_cmd[fr]));
1013 } else {
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),
1018 DBDMA_NOP, 0);
1019 eieio();
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;
1027 pb->last_fr = -2;
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]));
1041 eieio();
1042 } else {
1043 tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0);
1044 if(pb->gwidth[pb->prev_last_fr] !=
1045 pb->gwidth[fr]
1046 || pb->gheight[pb->prev_last_fr] !=
1047 pb->gheight[fr]
1048 || pb->gfmt[pb->prev_last_fr] !=
1049 pb->gfmt[fr])
1050 tab_cmd_dbdma((pb->cap_cmd[fr] + 1),
1051 DBDMA_NOP, 0);
1052 else
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]));
1059 eieio();
1061 tab_cmd_dbdma(pb->last_cmd[fr],
1062 DBDMA_NOP | BR_ALWAYS,
1063 virt_to_bus(pb->ch1_cmd));
1064 eieio();
1065 pb->prev_last_fr = fr;
1066 pb->last_fr = -2;
1067 } else {
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]));
1078 eieio();
1079 } else {
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] !=
1084 pb->gheight[fr]
1085 || pb->gfmt[pb->last_fr] !=
1086 pb->gfmt[fr])
1087 tab_cmd_dbdma((pb->cap_cmd[fr] + 1),
1088 DBDMA_NOP, 0);
1089 else
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]));
1096 eieio();
1098 pb->last_fr = fr;
1100 if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) {
1102 IDEBUG("PlanB: became inactive in the mean time..."
1103 "reactivating\n");
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);
1111 pb->grabbing++;
1112 planb_unlock(pb);
1114 return 0;
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);
1127 return;
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));
1151 cmd_tab_data_end:
1152 tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->cap_cmd[fr]));
1154 eieio();
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
1161 int scanline;
1162 #else
1163 int nlpp, leftover1;
1164 unsigned long base;
1165 #endif
1166 unsigned long jump;
1167 int pagei;
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;
1178 #else
1179 pb->lsize[fr] = count;
1180 pb->lnum[fr] = 0;
1181 #endif
1183 /* Do video in: */
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));
1205 if (interlace) {
1206 stepsize = 2;
1207 jump_addr = c1 + TAB_FACTOR * (nlines + 1) / 2;
1208 } else {
1209 stepsize = 1;
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);
1223 #else
1224 i = 0;
1225 leftover1 = 0;
1226 do {
1227 int j;
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);
1234 if(i < nlines) {
1235 int lov0 = PAGE_SIZE - count * nlpp * stepsize - leftover1;
1237 if(lov0 == 0)
1238 leftover1 = 0;
1239 else {
1240 if(lov0 >= count) {
1241 tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, base
1242 + count * nlpp * stepsize + leftover1, jump);
1243 } else {
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)
1252 pb->lnum[fr]--;
1254 leftover1 = count * stepsize - lov0;
1255 i += stepsize;
1258 pagei++;
1259 } while(i < nlines);
1260 tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, jump);
1261 c1 = jump_addr;
1262 #endif /* PLANB_GSCANLINE */
1264 /* For non-interlaced, we use even fields only */
1265 if (!interlace)
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);
1286 #else
1287 i = 1;
1288 leftover1 = 0;
1289 pagei = pb->gbuf_idx[fr];
1290 if(nlines <= 1)
1291 goto skip;
1292 do {
1293 int j;
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);
1300 i += stepsize;
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);
1305 if(i < nlines) {
1306 int lov0 = PAGE_SIZE - count * nlpp * stepsize - leftover1;
1308 if(lov0 == 0)
1309 leftover1 = 0;
1310 else {
1311 if(lov0 > count) {
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
1316 - lov0;
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)
1321 pb->lnum[fr]--;
1322 i += stepsize;
1324 leftover1 = count * stepsize - lov0;
1327 pagei++;
1328 } while(i < nlines);
1329 skip:
1330 tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, jump);
1331 c1 = jump_addr;
1332 #endif /* PLANB_GSCANLINE */
1334 cmd_tab_data_end:
1335 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->intr_stat),
1336 (fr << 9) | PLANB_FRM_IRQ | PLANB_GEN_IRQ);
1337 /* stop it */
1338 tab_cmd_dbdma(c1, DBDMA_STOP, 0);
1340 eieio();
1341 return c1;
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 */
1352 eieio();
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
1362 int i;
1363 #endif
1364 IDEBUG("PlanB: PLANB_FRM_IRQ\n");
1366 pb->gcount++;
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],
1378 first);
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]);
1383 #endif
1384 pb->frame_stat[fr] = GBUFFER_DONE;
1385 pb->grabbing--;
1386 wake_up_interruptible(&pb->capq);
1387 return;
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) {
1405 int err;
1406 if((err = planb_prepare_open(pb)) != 0)
1407 return err;
1409 pb->user++;
1411 DEBUG("PlanB: device opened\n");
1413 MOD_INC_USE_COUNT;
1414 return 0;
1417 static void planb_close(struct video_device *dev)
1419 struct planb *pb = (struct planb *)dev;
1421 if(pb->user < 1) /* ??? */
1422 return;
1423 planb_lock(pb);
1424 if (pb->user == 1) {
1425 if (pb->overlay) {
1426 planb_dbdma_stop(&pb->planb_base->ch2);
1427 planb_dbdma_stop(&pb->planb_base->ch1);
1428 pb->overlay = 0;
1430 planb_prepare_close(pb);
1432 pb->user--;
1433 planb_unlock(pb);
1435 DEBUG("PlanB: device closed\n");
1437 MOD_DEC_USE_COUNT;
1440 static long planb_read(struct video_device *v, char *buf, unsigned long count,
1441 int nonblock)
1443 DEBUG("planb: read request\n");
1444 return -EINVAL;
1447 static long planb_write(struct video_device *v, const char *buf,
1448 unsigned long count, int nonblock)
1450 DEBUG("planb: write request\n");
1451 return -EINVAL;
1454 static int planb_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
1456 struct planb *pb=(struct planb *)dev;
1458 switch (cmd)
1460 case VIDIOCGCAP:
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 |
1469 VID_TYPE_CAPTURE;
1470 b.channels = 2; /* composite & svhs */
1471 b.audios = 0;
1472 b.maxwidth = PLANB_MAXPIXELS;
1473 b.maxheight = PLANB_MAXLINES;
1474 b.minwidth = 32; /* wild guess */
1475 b.minheight = 32;
1476 if (copy_to_user(arg,&b,sizeof(b)))
1477 return -EFAULT;
1478 return 0;
1480 case VIDIOCSFBUF:
1482 struct video_buffer v;
1483 unsigned short bpp;
1484 unsigned int fmt;
1486 DEBUG("PlanB: IOCTL VIDIOCSFBUF\n");
1488 if (!capable(CAP_SYS_ADMIN)
1489 || !capable(CAP_SYS_RAWIO))
1490 return -EPERM;
1491 if (copy_from_user(&v, arg,sizeof(v)))
1492 return -EFAULT;
1493 planb_lock(pb);
1494 switch(v.depth) {
1495 case 8:
1496 bpp = 1;
1497 fmt = PLANB_GRAY;
1498 break;
1499 case 15:
1500 case 16:
1501 bpp = 2;
1502 fmt = PLANB_COLOUR15;
1503 break;
1504 case 24:
1505 case 32:
1506 bpp = 4;
1507 fmt = PLANB_COLOUR32;
1508 break;
1509 default:
1510 planb_unlock(pb);
1511 return -EINVAL;
1513 if (bpp * v.width > v.bytesperline) {
1514 planb_unlock(pb);
1515 return -EINVAL;
1517 pb->win.bpp = bpp;
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;
1531 if(pb->overlay) {
1532 suspend_overlay(pb);
1533 fill_cmd_buff(pb);
1534 resume_overlay(pb);
1536 planb_unlock(pb);
1537 return 0;
1539 case VIDIOCGFBUF:
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)))
1551 return -EFAULT;
1552 return 0;
1554 case VIDIOCCAPTURE:
1556 int i;
1558 if(copy_from_user(&i, arg, sizeof(i)))
1559 return -EFAULT;
1560 if(i==0) {
1561 DEBUG("PlanB: IOCTL VIDIOCCAPTURE Stop\n");
1563 if (!(pb->overlay))
1564 return 0;
1565 planb_lock(pb);
1566 pb->overlay = 0;
1567 overlay_stop(pb);
1568 planb_unlock(pb);
1569 } else {
1570 DEBUG("PlanB: IOCTL VIDIOCCAPTURE Start\n");
1572 if (pb->frame_buffer_phys == 0 ||
1573 pb->win.width == 0 ||
1574 pb->win.height == 0)
1575 return -EINVAL;
1576 if (pb->overlay)
1577 return 0;
1578 planb_lock(pb);
1579 pb->overlay = 1;
1580 if(!(pb->cmd_buff_inited))
1581 fill_cmd_buff(pb);
1582 overlay_start(pb);
1583 planb_unlock(pb);
1585 return 0;
1587 case VIDIOCGCHAN:
1589 struct video_channel v;
1591 DEBUG("PlanB: IOCTL VIDIOCGCHAN\n");
1593 if(copy_from_user(&v, arg,sizeof(v)))
1594 return -EFAULT;
1595 v.flags = 0;
1596 v.tuners = 0;
1597 v.type = VIDEO_TYPE_CAMERA;
1598 v.norm = pb->win.norm;
1599 switch(v.channel)
1601 case 0:
1602 strcpy(v.name,"Composite");
1603 break;
1604 case 1:
1605 strcpy(v.name,"SVHS");
1606 break;
1607 default:
1608 return -EINVAL;
1609 break;
1611 if(copy_to_user(arg,&v,sizeof(v)))
1612 return -EFAULT;
1614 return 0;
1616 case VIDIOCSCHAN:
1618 struct video_channel v;
1620 DEBUG("PlanB: IOCTL VIDIOCSCHAN\n");
1622 if(copy_from_user(&v, arg, sizeof(v)))
1623 return -EFAULT;
1625 if (v.norm != pb->win.norm) {
1626 int i, maxlines;
1628 switch (v.norm)
1630 case VIDEO_MODE_PAL:
1631 case VIDEO_MODE_SECAM:
1632 maxlines = PLANB_MAXLINES;
1633 break;
1634 case VIDEO_MODE_NTSC:
1635 maxlines = PLANB_NTSC_MAXLINES;
1636 break;
1637 default:
1638 return -EINVAL;
1639 break;
1641 planb_lock(pb);
1642 /* empty the grabbing queue */
1643 while(pb->grabbing)
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.... */
1652 fill_cmd_buff(pb);
1653 /* ok, now init it accordingly */
1654 saa_init_regs (pb);
1655 /* restart overlay if it was running */
1656 resume_overlay(pb);
1657 planb_unlock(pb);
1660 switch(v.channel)
1662 case 0: /* Composite */
1663 saa_set (SAA7196_IOCC,
1664 ((saa_regs[pb->win.norm][SAA7196_IOCC] &
1665 ~7) | 3), pb);
1666 break;
1667 case 1: /* SVHS */
1668 saa_set (SAA7196_IOCC,
1669 ((saa_regs[pb->win.norm][SAA7196_IOCC] &
1670 ~7) | 4), pb);
1671 break;
1672 default:
1673 return -EINVAL;
1674 break;
1677 return 0;
1679 case VIDIOCGPICT:
1681 struct video_picture vp = pb->picture;
1683 DEBUG("PlanB: IOCTL VIDIOCGPICT\n");
1685 switch(pb->win.color_fmt) {
1686 case PLANB_GRAY:
1687 vp.palette = VIDEO_PALETTE_GREY;
1688 case PLANB_COLOUR15:
1689 vp.palette = VIDEO_PALETTE_RGB555;
1690 break;
1691 case PLANB_COLOUR32:
1692 vp.palette = VIDEO_PALETTE_RGB32;
1693 break;
1694 default:
1695 vp.palette = 0;
1696 break;
1699 if(copy_to_user(arg,&vp,sizeof(vp)))
1700 return -EFAULT;
1701 return 0;
1703 case VIDIOCSPICT:
1705 struct video_picture vp;
1707 DEBUG("PlanB: IOCTL VIDIOCSPICT\n");
1709 if(copy_from_user(&vp,arg,sizeof(vp)))
1710 return -EFAULT;
1711 pb->picture = 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);
1722 return 0;
1724 case VIDIOCSWIN:
1726 struct video_window vw;
1727 struct video_clip clip;
1728 int i;
1730 DEBUG("PlanB: IOCTL VIDIOCSWIN\n");
1732 if(copy_from_user(&vw,arg,sizeof(vw)))
1733 return -EFAULT;
1735 planb_lock(pb);
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) {
1744 pb->win.x = vw.x;
1745 pb->win.y = vw.y;
1746 pb->win.width = vw.width;
1747 pb->win.height = vw.height;
1748 fill_cmd_buff(pb);
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)))
1757 return -EFAULT;
1758 add_clip(pb, &clip);
1760 /* restart overlay if it was running */
1761 resume_overlay(pb);
1762 planb_unlock(pb);
1763 return 0;
1765 case VIDIOCGWIN:
1767 struct video_window vw;
1769 DEBUG("PlanB: IOCTL VIDIOCGWIN\n");
1771 vw.x=pb->win.x;
1772 vw.y=pb->win.y;
1773 vw.width=pb->win.width;
1774 vw.height=pb->win.height;
1775 vw.chromakey=0;
1776 vw.flags=0;
1777 if(pb->win.interlace)
1778 vw.flags|=VIDEO_WINDOW_INTERLACE;
1779 if(copy_to_user(arg,&vw,sizeof(vw)))
1780 return -EFAULT;
1781 return 0;
1783 case VIDIOCSYNC: {
1784 int i;
1786 IDEBUG("PlanB: IOCTL VIDIOCSYNC\n");
1788 if(copy_from_user((void *)&i,arg,sizeof(int)))
1789 return -EFAULT;
1791 IDEBUG("PlanB: sync to frame %d\n", i);
1793 if(i > (MAX_GBUFFERS - 1) || i < 0)
1794 return -EINVAL;
1795 chk_grab:
1796 switch (pb->frame_stat[i]) {
1797 case GBUFFER_UNUSED:
1798 return -EINVAL;
1799 case GBUFFER_GRABBING:
1800 IDEBUG("PlanB: waiting for grab"
1801 " done (%d)\n", i);
1802 interruptible_sleep_on(&pb->capq);
1803 if(signal_pending(current))
1804 return -EINTR;
1805 goto chk_grab;
1806 case GBUFFER_DONE:
1807 pb->frame_stat[i] = GBUFFER_UNUSED;
1808 break;
1810 return 0;
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)))
1821 return -EFAULT;
1822 status = pb->frame_stat[vm.frame];
1823 if (status != GBUFFER_UNUSED)
1824 return -EBUSY;
1826 return vgrab(pb, &vm);
1829 case VIDIOCGMBUF:
1831 int i;
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)))
1842 return -EFAULT;
1843 return 0;
1846 case PLANBIOCGSAAREGS:
1848 struct planb_saa_regs preg;
1850 DEBUG("PlanB: IOCTL PLANBIOCGSAAREGS\n");
1852 if(copy_from_user(&preg, arg, sizeof(preg)))
1853 return -EFAULT;
1854 if(preg.addr >= SAA7196_NUMREGS)
1855 return -EINVAL;
1856 preg.val = saa_regs[pb->win.norm][preg.addr];
1857 if(copy_to_user((void *)arg, (void *)&preg,
1858 sizeof(preg)))
1859 return -EFAULT;
1860 return 0;
1863 case PLANBIOCSSAAREGS:
1865 struct planb_saa_regs preg;
1867 DEBUG("PlanB: IOCTL PLANBIOCSSAAREGS\n");
1869 if(copy_from_user(&preg, arg, sizeof(preg)))
1870 return -EFAULT;
1871 if(preg.addr >= SAA7196_NUMREGS)
1872 return -EINVAL;
1873 saa_set (preg.addr, preg.val, pb);
1874 return 0;
1877 case PLANBIOCGSTAT:
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,
1889 sizeof(pstat)))
1890 return -EFAULT;
1891 return 0;
1894 case PLANBIOCSMODE: {
1895 int v;
1897 DEBUG("PlanB: IOCTL PLANBIOCSMODE\n");
1899 if(copy_from_user(&v, arg, sizeof(v)))
1900 return -EFAULT;
1902 switch(v)
1904 case PLANB_TV_MODE:
1905 saa_set (SAA7196_STDC,
1906 (saa_regs[pb->win.norm][SAA7196_STDC] &
1907 0x7f), pb);
1908 break;
1909 case PLANB_VTR_MODE:
1910 saa_set (SAA7196_STDC,
1911 (saa_regs[pb->win.norm][SAA7196_STDC] |
1912 0x80), pb);
1913 break;
1914 default:
1915 return -EINVAL;
1916 break;
1918 pb->win.mode = v;
1919 return 0;
1921 case PLANBIOCGMODE: {
1922 int v=pb->win.mode;
1924 DEBUG("PlanB: IOCTL PLANBIOCGMODE\n");
1926 if(copy_to_user(arg,&v,sizeof(v)))
1927 return -EFAULT;
1928 return 0;
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)))
1937 return -EFAULT;
1938 return 0;
1940 #endif /* PLANB_GSCANLINE */
1941 case PLANB_INTR_DEBUG: {
1942 int i;
1944 DEBUG("PlanB: IOCTL PLANB_INTR_DEBUG\n");
1946 if(copy_from_user(&i, arg, sizeof(i)))
1947 return -EFAULT;
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;
1955 if(pb->grabbing)
1956 pb->grabbing--;
1957 wake_up_interruptible(&pb->capq);
1958 return 0;
1960 case PLANB_INV_REGS: {
1961 int i;
1962 struct planb_any_regs any;
1964 DEBUG("PlanB: IOCTL PLANB_INV_REGS\n");
1966 if(copy_from_user(&any, arg, sizeof(any)))
1967 return -EFAULT;
1968 if(any.offset < 0 || any.offset + any.bytes > 0x400)
1969 return -EINVAL;
1970 if(any.bytes > 128)
1971 return -EINVAL;
1972 for (i = 0; i < any.bytes; i++) {
1973 any.data[i] =
1974 in_8((unsigned char *)pb->planb_base
1975 + any.offset + i);
1977 if(copy_to_user(arg,&any,sizeof(any)))
1978 return -EFAULT;
1979 return 0;
1981 default:
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; }
1993 case VIDIOCSFREQ: {
1994 DEBUG("PlanB: IOCTL VIDIOCSFREQ\n");
1995 goto unimplemented; }
1996 case VIDIOCGFREQ: {
1997 DEBUG("PlanB: IOCTL VIDIOCGFREQ\n");
1998 goto unimplemented; }
1999 case VIDIOCKEY: {
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; }
2008 unimplemented:
2009 DEBUG(" Unimplemented\n");
2010 return -ENOIOCTLCMD;
2012 return 0;
2015 static int planb_mmap(struct video_device *dev, const char *adr, unsigned long size)
2017 int i;
2018 struct planb *pb = (struct planb *)dev;
2019 unsigned long start = (unsigned long)adr;
2021 if (size > MAX_GBUFFERS * PLANB_MAX_FBUF)
2022 return -EINVAL;
2023 if (!pb->rawbuf) {
2024 int err;
2025 if((err=grabbuf_alloc(pb)))
2026 return err;
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))
2031 return -EAGAIN;
2032 start += PAGE_SIZE;
2033 if (size <= PAGE_SIZE)
2034 break;
2035 size -= PAGE_SIZE;
2037 return 0;
2040 /* This gets called upon device registration */
2041 /* we could do some init here */
2042 static int planb_init_done(struct video_device *dev)
2044 return 0;
2047 static struct video_device planb_template=
2049 PLANB_DEVICE_NAME,
2050 VID_TYPE_OVERLAY,
2051 VID_HARDWARE_PLANB,
2052 planb_open,
2053 planb_close,
2054 planb_read,
2055 planb_write,
2056 #if LINUX_VERSION_CODE >= 0x020100
2057 NULL, /* poll */
2058 #endif
2059 planb_ioctl,
2060 planb_mmap, /* mmap? */
2061 planb_init_done,
2062 NULL, /* pointer to private data */
2067 static int init_planb(struct planb *pb)
2069 unsigned char saa_rev;
2070 int i, result;
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");
2077 return -2;
2079 pb->win.norm = def_norm;
2080 pb->win.mode = PLANB_TV_MODE; /* TV mode */
2081 pb->win.interlace=1;
2082 pb->win.x=0;
2083 pb->win.y=0;
2084 pb->win.width=768; /* 640 */
2085 pb->win.height=576; /* 480 */
2086 pb->maxlines=576;
2087 #if 0
2088 btv->win.cropwidth=768; /* 640 */
2089 btv->win.cropheight=576; /* 480 */
2090 btv->win.cropx=0;
2091 btv->win.cropy=0;
2092 #endif
2093 pb->win.pad=0;
2094 pb->win.bpp=4;
2095 pb->win.depth=32;
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))
2103 return -3;
2104 else {
2105 /* page align pb->gbytes_per_line for DMA purpose */
2106 for(i = PAGE_SIZE; pb->gbytes_per_line < (i>>1);)
2107 i>>=1;
2108 pb->gbytes_per_line = i;
2110 #endif
2111 pb->tab_size = PLANB_MAXLINES + 40;
2112 pb->suspend = 0;
2113 pb->lock = 0;
2114 init_waitqueue_head(&pb->lockq);
2115 pb->ch1_cmd = 0;
2116 pb->ch2_cmd = 0;
2117 pb->mask = 0;
2118 pb->priv_space = 0;
2119 pb->offset = 0;
2120 pb->user = 0;
2121 pb->overlay = 0;
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 */
2133 saa_init_regs (pb);
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);
2140 if (result < 0) {
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);
2148 return result;
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;
2167 pb->gwidth[i]=0;
2168 pb->gheight[i]=0;
2169 pb->gfmt[i]=0;
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;
2174 pb->lsize[i] = 0;
2175 pb->lnum[i] = 0;
2176 #endif
2178 pb->rawbuf=NULL;
2179 pb->grabbing=0;
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)
2187 return -1;
2189 return 0;
2193 * Scan for a PlanB controller, request the irq and map the io memory
2196 static int find_planb(void)
2198 struct planb *pb;
2199 struct device_node *planb_devices;
2200 unsigned char dev_fn, confreg, bus;
2201 unsigned int old_base, new_base;
2202 unsigned int irq;
2203 struct pci_dev *pdev;
2205 if (_machine != _MACH_Pmac)
2206 return 0;
2208 planb_devices = find_devices("planb");
2209 if (planb_devices == 0) {
2210 planb_num=0;
2211 printk(KERN_WARNING "PlanB: no device found!\n");
2212 return planb_num;
2215 if (planb_devices->next != NULL)
2216 printk(KERN_ERR "Warning: only using first PlanB device!\n");
2217 pb = &planbs[0];
2218 planb_num = 1;
2220 if (planb_devices->n_addrs != 1) {
2221 printk (KERN_WARNING "PlanB: expecting 1 address for planb "
2222 "(got %d)", planb_devices->n_addrs);
2223 return 0;
2226 if (planb_devices->n_intrs == 0) {
2227 printk(KERN_WARNING "PlanB: no intrs for device %s\n",
2228 planb_devices->full_name);
2229 return 0;
2230 } else {
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);
2256 if (!pdev) {
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;
2277 pb->irq = irq;
2279 return planb_num;
2282 static void release_planb(void)
2284 int i;
2285 struct planb *pb;
2287 for (i=0;i<planb_num; i++)
2289 pb=&planbs[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);
2311 #ifdef MODULE
2313 int init_module(void)
2315 #else
2316 int __init init_planbs(struct video_init *unused)
2318 #endif
2319 int i;
2321 if (find_planb()<=0)
2322 return -EIO;
2324 for (i=0; i<planb_num; i++) {
2325 if (init_planb(&planbs[i])<0) {
2326 printk(KERN_ERR "PlanB: error registering device %d"
2327 " with v4l\n", i);
2328 release_planb();
2329 return -EIO;
2331 printk(KERN_INFO "PlanB: registered device %d with v4l\n", i);
2333 return 0;
2336 #ifdef MODULE
2338 void cleanup_module(void)
2340 release_planb();
2343 #endif