initial commit with v2.6.9
[linux-2.6.9-moxart.git] / drivers / media / video / planb.c
blobebf130f167e354d9beb9c63678a64b43edab143c
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/init.h>
31 #include <linux/errno.h>
32 #include <linux/module.h>
33 #include <linux/kernel.h>
34 #include <linux/major.h>
35 #include <linux/slab.h>
36 #include <linux/types.h>
37 #include <linux/pci.h>
38 #include <linux/delay.h>
39 #include <linux/vmalloc.h>
40 #include <linux/mm.h>
41 #include <linux/sched.h>
42 #include <linux/videodev.h>
43 #include <asm/uaccess.h>
44 #include <asm/io.h>
45 #include <asm/prom.h>
46 #include <asm/dbdma.h>
47 #include <asm/pgtable.h>
48 #include <asm/page.h>
49 #include <asm/irq.h>
50 #include <asm/semaphore.h>
52 #include "planb.h"
53 #include "saa7196.h"
55 /* Would you mind for some ugly debugging? */
56 #if 0
57 #define DEBUG(x...) printk(KERN_DEBUG ## x) /* Debug driver */
58 #else
59 #define DEBUG(x...) /* Don't debug driver */
60 #endif
62 #if 0
63 #define IDEBUG(x...) printk(KERN_DEBUG ## x) /* Debug interrupt part */
64 #else
65 #define IDEBUG(x...) /* Don't debug interrupt part */
66 #endif
68 /* Ever seen a Mac with more than 1 of these? */
69 #define PLANB_MAX 1
71 static int planb_num;
72 static struct planb planbs[PLANB_MAX];
73 static volatile struct planb_registers *planb_regs;
75 static int def_norm = PLANB_DEF_NORM; /* default norm */
76 static int video_nr = -1;
78 MODULE_PARM(def_norm, "i");
79 MODULE_PARM_DESC(def_norm, "Default startup norm (0=PAL, 1=NTSC, 2=SECAM)");
80 MODULE_PARM(video_nr,"i");
81 MODULE_LICENSE("GPL");
84 /* ------------------ PlanB Exported Functions ------------------ */
85 static long planb_write(struct video_device *, const char *, unsigned long, int);
86 static long planb_read(struct video_device *, char *, unsigned long, int);
87 static int planb_open(struct video_device *, int);
88 static void planb_close(struct video_device *);
89 static int planb_ioctl(struct video_device *, unsigned int, void *);
90 static int planb_init_done(struct video_device *);
91 static int planb_mmap(struct video_device *, const char *, unsigned long);
92 static void planb_irq(int, void *, struct pt_regs *);
93 static void release_planb(void);
94 int init_planbs(struct video_init *);
96 /* ------------------ PlanB Internal Functions ------------------ */
97 static int planb_prepare_open(struct planb *);
98 static void planb_prepare_close(struct planb *);
99 static void saa_write_reg(unsigned char, unsigned char);
100 static unsigned char saa_status(int, struct planb *);
101 static void saa_set(unsigned char, unsigned char, struct planb *);
102 static void saa_init_regs(struct planb *);
103 static int grabbuf_alloc(struct planb *);
104 static int vgrab(struct planb *, struct video_mmap *);
105 static void add_clip(struct planb *, struct video_clip *);
106 static void fill_cmd_buff(struct planb *);
107 static void cmd_buff(struct planb *);
108 static volatile struct dbdma_cmd *setup_grab_cmd(int, struct planb *);
109 static void overlay_start(struct planb *);
110 static void overlay_stop(struct planb *);
111 static inline void tab_cmd_dbdma(volatile struct dbdma_cmd *, unsigned short,
112 unsigned int);
113 static inline void tab_cmd_store(volatile struct dbdma_cmd *, unsigned int,
114 unsigned int);
115 static inline void tab_cmd_gen(volatile struct dbdma_cmd *, unsigned short,
116 unsigned short, unsigned int, unsigned int);
117 static int init_planb(struct planb *);
118 static int find_planb(void);
119 static void planb_pre_capture(int, int, struct planb *);
120 static volatile struct dbdma_cmd *cmd_geo_setup(volatile struct dbdma_cmd *,
121 int, int, int, int, int, struct planb *);
122 static inline void planb_dbdma_stop(volatile struct dbdma_regs *);
123 static unsigned int saa_geo_setup(int, int, int, int, struct planb *);
124 static inline int overlay_is_active(struct planb *);
126 /*******************************/
127 /* Memory management functions */
128 /*******************************/
130 static int grabbuf_alloc(struct planb *pb)
132 int i, npage;
134 npage = MAX_GBUFFERS * ((PLANB_MAX_FBUF / PAGE_SIZE + 1)
135 #ifndef PLANB_GSCANLINE
136 + MAX_LNUM
137 #endif /* PLANB_GSCANLINE */
139 if ((pb->rawbuf = (unsigned char**) kmalloc (npage
140 * sizeof(unsigned long), GFP_KERNEL)) == 0)
141 return -ENOMEM;
142 for (i = 0; i < npage; i++) {
143 pb->rawbuf[i] = (unsigned char *)__get_free_pages(GFP_KERNEL
144 |GFP_DMA, 0);
145 if (!pb->rawbuf[i])
146 break;
147 SetPageReserved(virt_to_page(pb->rawbuf[i]));
149 if (i-- < npage) {
150 printk(KERN_DEBUG "PlanB: init_grab: grab buffer not allocated\n");
151 for (; i > 0; i--) {
152 ClearPageReserved(virt_to_page(pb->rawbuf[i]));
153 free_pages((unsigned long)pb->rawbuf[i], 0);
155 kfree(pb->rawbuf);
156 return -ENOBUFS;
158 pb->rawbuf_size = npage;
159 return 0;
162 /*****************************/
163 /* Hardware access functions */
164 /*****************************/
166 static void saa_write_reg(unsigned char addr, unsigned char val)
168 planb_regs->saa_addr = addr; eieio();
169 planb_regs->saa_regval = val; eieio();
170 return;
173 /* return status byte 0 or 1: */
174 static unsigned char saa_status(int byte, struct planb *pb)
176 saa_regs[pb->win.norm][SAA7196_STDC] =
177 (saa_regs[pb->win.norm][SAA7196_STDC] & ~2) | ((byte & 1) << 1);
178 saa_write_reg (SAA7196_STDC, saa_regs[pb->win.norm][SAA7196_STDC]);
180 /* Let's wait 30msec for this one */
181 current->state = TASK_INTERRUPTIBLE;
182 schedule_timeout(30 * HZ / 1000);
184 return (unsigned char)in_8 (&planb_regs->saa_status);
187 static void saa_set(unsigned char addr, unsigned char val, struct planb *pb)
189 if(saa_regs[pb->win.norm][addr] != val) {
190 saa_regs[pb->win.norm][addr] = val;
191 saa_write_reg (addr, val);
193 return;
196 static void saa_init_regs(struct planb *pb)
198 int i;
200 for (i = 0; i < SAA7196_NUMREGS; i++)
201 saa_write_reg (i, saa_regs[pb->win.norm][i]);
204 static unsigned int saa_geo_setup(int width, int height, int interlace, int bpp,
205 struct planb *pb)
207 int ht, norm = pb->win.norm;
209 switch(bpp) {
210 case 2:
211 /* RGB555+a 1x16-bit + 16-bit transparent */
212 saa_regs[norm][SAA7196_FMTS] &= ~0x3;
213 break;
214 case 1:
215 case 4:
216 /* RGB888 1x24-bit + 8-bit transparent */
217 saa_regs[norm][SAA7196_FMTS] &= ~0x1;
218 saa_regs[norm][SAA7196_FMTS] |= 0x2;
219 break;
220 default:
221 return -EINVAL;
223 ht = (interlace ? height / 2 : height);
224 saa_regs[norm][SAA7196_OUTPIX] = (unsigned char) (width & 0x00ff);
225 saa_regs[norm][SAA7196_HFILT] = (saa_regs[norm][SAA7196_HFILT] & ~0x3)
226 | (width >> 8 & 0x3);
227 saa_regs[norm][SAA7196_OUTLINE] = (unsigned char) (ht & 0xff);
228 saa_regs[norm][SAA7196_VYP] = (saa_regs[norm][SAA7196_VYP] & ~0x3)
229 | (ht >> 8 & 0x3);
230 /* feed both fields if interlaced, or else feed only even fields */
231 saa_regs[norm][SAA7196_FMTS] = (interlace) ?
232 (saa_regs[norm][SAA7196_FMTS] & ~0x60)
233 : (saa_regs[norm][SAA7196_FMTS] | 0x60);
234 /* transparent mode; extended format enabled */
235 saa_regs[norm][SAA7196_DPATH] |= 0x3;
237 return 0;
240 /***************************/
241 /* DBDMA support functions */
242 /***************************/
244 static inline void planb_dbdma_restart(volatile struct dbdma_regs *ch)
246 out_le32(&ch->control, PLANB_CLR(RUN));
247 out_le32(&ch->control, PLANB_SET(RUN|WAKE) | PLANB_CLR(PAUSE));
250 static inline void planb_dbdma_stop(volatile struct dbdma_regs *ch)
252 int i = 0;
254 out_le32(&ch->control, PLANB_CLR(RUN) | PLANB_SET(FLUSH));
255 while((in_le32(&ch->status) == (ACTIVE | FLUSH)) && (i < 999)) {
256 IDEBUG("PlanB: waiting for DMA to stop\n");
257 i++;
261 static inline void tab_cmd_dbdma(volatile struct dbdma_cmd *ch,
262 unsigned short command, unsigned int cmd_dep)
264 st_le16(&ch->command, command);
265 st_le32(&ch->cmd_dep, cmd_dep);
268 static inline void tab_cmd_store(volatile struct dbdma_cmd *ch,
269 unsigned int phy_addr, unsigned int cmd_dep)
271 st_le16(&ch->command, STORE_WORD | KEY_SYSTEM);
272 st_le16(&ch->req_count, 4);
273 st_le32(&ch->phy_addr, phy_addr);
274 st_le32(&ch->cmd_dep, cmd_dep);
277 static inline void tab_cmd_gen(volatile struct dbdma_cmd *ch,
278 unsigned short command, unsigned short req_count,
279 unsigned int phy_addr, unsigned int cmd_dep)
281 st_le16(&ch->command, command);
282 st_le16(&ch->req_count, req_count);
283 st_le32(&ch->phy_addr, phy_addr);
284 st_le32(&ch->cmd_dep, cmd_dep);
287 static volatile struct dbdma_cmd *cmd_geo_setup(
288 volatile struct dbdma_cmd *c1, int width, int height, int interlace,
289 int bpp, int clip, struct planb *pb)
291 int norm = pb->win.norm;
293 if((saa_geo_setup(width, height, interlace, bpp, pb)) != 0)
294 return (volatile struct dbdma_cmd *)NULL;
295 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),
296 SAA7196_FMTS);
297 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),
298 saa_regs[norm][SAA7196_FMTS]);
299 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),
300 SAA7196_DPATH);
301 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),
302 saa_regs[norm][SAA7196_DPATH]);
303 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->even),
304 bpp | ((clip)? PLANB_CLIPMASK: 0));
305 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->odd),
306 bpp | ((clip)? PLANB_CLIPMASK: 0));
307 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),
308 SAA7196_OUTPIX);
309 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),
310 saa_regs[norm][SAA7196_OUTPIX]);
311 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),
312 SAA7196_HFILT);
313 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),
314 saa_regs[norm][SAA7196_HFILT]);
315 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),
316 SAA7196_OUTLINE);
317 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),
318 saa_regs[norm][SAA7196_OUTLINE]);
319 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),
320 SAA7196_VYP);
321 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),
322 saa_regs[norm][SAA7196_VYP]);
323 return c1;
326 /******************************/
327 /* misc. supporting functions */
328 /******************************/
330 static inline void planb_lock(struct planb *pb)
332 down(&pb->lock);
335 static inline void planb_unlock(struct planb *pb)
337 up(&pb->lock);
340 /***************/
341 /* Driver Core */
342 /***************/
344 static int planb_prepare_open(struct planb *pb)
346 int i, size;
348 /* allocate memory for two plus alpha command buffers (size: max lines,
349 plus 40 commands handling, plus 1 alignment), plus dummy command buf,
350 plus clipmask buffer, plus frame grabbing status */
351 size = (pb->tab_size*(2+MAX_GBUFFERS*TAB_FACTOR)+1+MAX_GBUFFERS
352 * PLANB_DUMMY)*sizeof(struct dbdma_cmd)
353 +(PLANB_MAXLINES*((PLANB_MAXPIXELS+7)& ~7))/8
354 +MAX_GBUFFERS*sizeof(unsigned int);
355 if ((pb->priv_space = kmalloc (size, GFP_KERNEL)) == 0)
356 return -ENOMEM;
357 memset ((void *) pb->priv_space, 0, size);
358 pb->overlay_last1 = pb->ch1_cmd = (volatile struct dbdma_cmd *)
359 DBDMA_ALIGN (pb->priv_space);
360 pb->overlay_last2 = pb->ch2_cmd = pb->ch1_cmd + pb->tab_size;
361 pb->ch1_cmd_phys = virt_to_bus(pb->ch1_cmd);
362 pb->cap_cmd[0] = pb->ch2_cmd + pb->tab_size;
363 pb->pre_cmd[0] = pb->cap_cmd[0] + pb->tab_size * TAB_FACTOR;
364 for (i = 1; i < MAX_GBUFFERS; i++) {
365 pb->cap_cmd[i] = pb->pre_cmd[i-1] + PLANB_DUMMY;
366 pb->pre_cmd[i] = pb->cap_cmd[i] + pb->tab_size * TAB_FACTOR;
368 pb->frame_stat=(volatile unsigned int *)(pb->pre_cmd[MAX_GBUFFERS-1]
369 + PLANB_DUMMY);
370 pb->mask = (unsigned char *)(pb->frame_stat+MAX_GBUFFERS);
372 pb->rawbuf = NULL;
373 pb->rawbuf_size = 0;
374 pb->grabbing = 0;
375 for (i = 0; i < MAX_GBUFFERS; i++) {
376 pb->frame_stat[i] = GBUFFER_UNUSED;
377 pb->gwidth[i] = 0;
378 pb->gheight[i] = 0;
379 pb->gfmt[i] = 0;
380 pb->gnorm_switch[i] = 0;
381 #ifndef PLANB_GSCANLINE
382 pb->lsize[i] = 0;
383 pb->lnum[i] = 0;
384 #endif /* PLANB_GSCANLINE */
386 pb->gcount = 0;
387 pb->suspend = 0;
388 pb->last_fr = -999;
389 pb->prev_last_fr = -999;
391 /* Reset DMA controllers */
392 planb_dbdma_stop(&pb->planb_base->ch2);
393 planb_dbdma_stop(&pb->planb_base->ch1);
395 return 0;
398 static void planb_prepare_close(struct planb *pb)
400 int i;
402 /* make sure the dma's are idle */
403 planb_dbdma_stop(&pb->planb_base->ch2);
404 planb_dbdma_stop(&pb->planb_base->ch1);
405 /* free kernel memory of command buffers */
406 if(pb->priv_space != 0) {
407 kfree (pb->priv_space);
408 pb->priv_space = 0;
409 pb->cmd_buff_inited = 0;
411 if(pb->rawbuf) {
412 for (i = 0; i < pb->rawbuf_size; i++) {
413 ClearPageReserved(virt_to_page(pb->rawbuf[i]));
414 free_pages((unsigned long)pb->rawbuf[i], 0);
416 kfree(pb->rawbuf);
418 pb->rawbuf = NULL;
421 /*****************************/
422 /* overlay support functions */
423 /*****************************/
425 static void overlay_start(struct planb *pb)
428 DEBUG("PlanB: overlay_start()\n");
430 if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) {
432 DEBUG("PlanB: presumably, grabbing is in progress...\n");
434 planb_dbdma_stop(&pb->planb_base->ch2);
435 out_le32 (&pb->planb_base->ch2.cmdptr,
436 virt_to_bus(pb->ch2_cmd));
437 planb_dbdma_restart(&pb->planb_base->ch2);
438 st_le16 (&pb->ch1_cmd->command, DBDMA_NOP);
439 tab_cmd_dbdma(pb->last_cmd[pb->last_fr],
440 DBDMA_NOP | BR_ALWAYS,
441 virt_to_bus(pb->ch1_cmd));
442 eieio();
443 pb->prev_last_fr = pb->last_fr;
444 pb->last_fr = -2;
445 if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) {
446 IDEBUG("PlanB: became inactive "
447 "in the mean time... reactivating\n");
448 planb_dbdma_stop(&pb->planb_base->ch1);
449 out_le32 (&pb->planb_base->ch1.cmdptr,
450 virt_to_bus(pb->ch1_cmd));
451 planb_dbdma_restart(&pb->planb_base->ch1);
453 } else {
455 DEBUG("PlanB: currently idle, so can do whatever\n");
457 planb_dbdma_stop(&pb->planb_base->ch2);
458 planb_dbdma_stop(&pb->planb_base->ch1);
459 st_le32 (&pb->planb_base->ch2.cmdptr,
460 virt_to_bus(pb->ch2_cmd));
461 st_le32 (&pb->planb_base->ch1.cmdptr,
462 virt_to_bus(pb->ch1_cmd));
463 out_le16 (&pb->ch1_cmd->command, DBDMA_NOP);
464 planb_dbdma_restart(&pb->planb_base->ch2);
465 planb_dbdma_restart(&pb->planb_base->ch1);
466 pb->last_fr = -1;
468 return;
471 static void overlay_stop(struct planb *pb)
473 DEBUG("PlanB: overlay_stop()\n");
475 if(pb->last_fr == -1) {
477 DEBUG("PlanB: no grabbing, it seems...\n");
479 planb_dbdma_stop(&pb->planb_base->ch2);
480 planb_dbdma_stop(&pb->planb_base->ch1);
481 pb->last_fr = -999;
482 } else if(pb->last_fr == -2) {
483 unsigned int cmd_dep;
484 tab_cmd_dbdma(pb->cap_cmd[pb->prev_last_fr], DBDMA_STOP, 0);
485 eieio();
486 cmd_dep = (unsigned int)in_le32(&pb->overlay_last1->cmd_dep);
487 if(overlay_is_active(pb)) {
489 DEBUG("PlanB: overlay is currently active\n");
491 planb_dbdma_stop(&pb->planb_base->ch2);
492 planb_dbdma_stop(&pb->planb_base->ch1);
493 if(cmd_dep != pb->ch1_cmd_phys) {
494 out_le32(&pb->planb_base->ch1.cmdptr,
495 virt_to_bus(pb->overlay_last1));
496 planb_dbdma_restart(&pb->planb_base->ch1);
499 pb->last_fr = pb->prev_last_fr;
500 pb->prev_last_fr = -999;
502 return;
505 static void suspend_overlay(struct planb *pb)
507 int fr = -1;
508 struct dbdma_cmd last;
510 DEBUG("PlanB: suspend_overlay: %d\n", pb->suspend);
512 if(pb->suspend++)
513 return;
514 if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) {
515 if(pb->last_fr == -2) {
516 fr = pb->prev_last_fr;
517 memcpy(&last, (void*)pb->last_cmd[fr], sizeof(last));
518 tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0);
520 if(overlay_is_active(pb)) {
521 planb_dbdma_stop(&pb->planb_base->ch2);
522 planb_dbdma_stop(&pb->planb_base->ch1);
523 pb->suspended.overlay = 1;
524 pb->suspended.frame = fr;
525 memcpy(&pb->suspended.cmd, &last, sizeof(last));
526 return;
529 pb->suspended.overlay = 0;
530 pb->suspended.frame = fr;
531 memcpy(&pb->suspended.cmd, &last, sizeof(last));
532 return;
535 static void resume_overlay(struct planb *pb)
538 DEBUG("PlanB: resume_overlay: %d\n", pb->suspend);
540 if(pb->suspend > 1)
541 return;
542 if(pb->suspended.frame != -1) {
543 memcpy((void*)pb->last_cmd[pb->suspended.frame],
544 &pb->suspended.cmd, sizeof(pb->suspended.cmd));
546 if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) {
547 goto finish;
549 if(pb->suspended.overlay) {
551 DEBUG("PlanB: overlay being resumed\n");
553 st_le16 (&pb->ch1_cmd->command, DBDMA_NOP);
554 st_le16 (&pb->ch2_cmd->command, DBDMA_NOP);
555 /* Set command buffer addresses */
556 st_le32(&pb->planb_base->ch1.cmdptr,
557 virt_to_bus(pb->overlay_last1));
558 out_le32(&pb->planb_base->ch2.cmdptr,
559 virt_to_bus(pb->overlay_last2));
560 /* Start the DMA controller */
561 out_le32 (&pb->planb_base->ch2.control,
562 PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE));
563 out_le32 (&pb->planb_base->ch1.control,
564 PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE));
565 } else if(pb->suspended.frame != -1) {
566 out_le32(&pb->planb_base->ch1.cmdptr,
567 virt_to_bus(pb->last_cmd[pb->suspended.frame]));
568 out_le32 (&pb->planb_base->ch1.control,
569 PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE));
572 finish:
573 pb->suspend--;
574 wake_up_interruptible(&pb->suspendq);
577 static void add_clip(struct planb *pb, struct video_clip *clip)
579 volatile unsigned char *base;
580 int xc = clip->x, yc = clip->y;
581 int wc = clip->width, hc = clip->height;
582 int ww = pb->win.width, hw = pb->win.height;
583 int x, y, xtmp1, xtmp2;
585 DEBUG("PlanB: clip %dx%d+%d+%d\n", wc, hc, xc, yc);
587 if(xc < 0) {
588 wc += xc;
589 xc = 0;
591 if(yc < 0) {
592 hc += yc;
593 yc = 0;
595 if(xc + wc > ww)
596 wc = ww - xc;
597 if(wc <= 0) /* Nothing to do */
598 return;
599 if(yc + hc > hw)
600 hc = hw - yc;
602 for (y = yc; y < yc+hc; y++) {
603 xtmp1=xc>>3;
604 xtmp2=(xc+wc)>>3;
605 base = pb->mask + y*96;
606 if(xc != 0 || wc >= 8)
607 *(base + xtmp1) &= (unsigned char)(0x00ff &
608 (0xff00 >> (xc&7)));
609 for (x = xtmp1 + 1; x < xtmp2; x++) {
610 *(base + x) = 0;
612 if(xc < (ww & ~0x7))
613 *(base + xtmp2) &= (unsigned char)(0x00ff >>
614 ((xc+wc) & 7));
617 return;
620 static void fill_cmd_buff(struct planb *pb)
622 int restore = 0;
623 volatile struct dbdma_cmd last;
625 DEBUG("PlanB: fill_cmd_buff()\n");
627 if(pb->overlay_last1 != pb->ch1_cmd) {
628 restore = 1;
629 last = *(pb->overlay_last1);
631 memset ((void *) pb->ch1_cmd, 0, 2 * pb->tab_size
632 * sizeof(struct dbdma_cmd));
633 cmd_buff (pb);
634 if(restore)
635 *(pb->overlay_last1) = last;
636 if(pb->suspended.overlay) {
637 unsigned long jump_addr = in_le32(&pb->overlay_last1->cmd_dep);
638 if(jump_addr != pb->ch1_cmd_phys) {
639 int i;
641 DEBUG("PlanB: adjusting ch1's jump address\n");
643 for(i = 0; i < MAX_GBUFFERS; i++) {
644 if(pb->need_pre_capture[i]) {
645 if(jump_addr == virt_to_bus(pb->pre_cmd[i]))
646 goto found;
647 } else {
648 if(jump_addr == virt_to_bus(pb->cap_cmd[i]))
649 goto found;
653 DEBUG("PlanB: not found...\n");
655 goto out;
656 found:
657 if(pb->need_pre_capture[i])
658 out_le32(&pb->pre_cmd[i]->phy_addr,
659 virt_to_bus(pb->overlay_last1));
660 else
661 out_le32(&pb->cap_cmd[i]->phy_addr,
662 virt_to_bus(pb->overlay_last1));
665 out:
666 pb->cmd_buff_inited = 1;
668 return;
671 static void cmd_buff(struct planb *pb)
673 int i, bpp, count, nlines, stepsize, interlace;
674 unsigned long base, jump, addr_com, addr_dep;
675 volatile struct dbdma_cmd *c1 = pb->ch1_cmd;
676 volatile struct dbdma_cmd *c2 = pb->ch2_cmd;
678 interlace = pb->win.interlace;
679 bpp = pb->win.bpp;
680 count = (bpp * ((pb->win.x + pb->win.width > pb->win.swidth) ?
681 (pb->win.swidth - pb->win.x) : pb->win.width));
682 nlines = ((pb->win.y + pb->win.height > pb->win.sheight) ?
683 (pb->win.sheight - pb->win.y) : pb->win.height);
685 /* Do video in: */
687 /* Preamble commands: */
688 addr_com = virt_to_bus(c1);
689 addr_dep = virt_to_bus(&c1->cmd_dep);
690 tab_cmd_dbdma(c1++, DBDMA_NOP, 0);
691 jump = virt_to_bus(c1+16); /* 14 by cmd_geo_setup() and 2 for padding */
692 if((c1 = cmd_geo_setup(c1, pb->win.width, pb->win.height, interlace,
693 bpp, 1, pb)) == NULL) {
694 printk(KERN_WARNING "PlanB: encountered serious problems\n");
695 tab_cmd_dbdma(pb->ch1_cmd + 1, DBDMA_STOP, 0);
696 tab_cmd_dbdma(pb->ch2_cmd + 1, DBDMA_STOP, 0);
697 return;
699 tab_cmd_store(c1++, addr_com, (unsigned)(DBDMA_NOP | BR_ALWAYS) << 16);
700 tab_cmd_store(c1++, addr_dep, jump);
701 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel),
702 PLANB_SET(FIELD_SYNC));
703 /* (1) wait for field sync to be set */
704 tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
705 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
706 PLANB_SET(ODD_FIELD));
707 /* wait for field sync to be cleared */
708 tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
709 /* if not odd field, wait until field sync is set again */
710 tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++;
711 /* assert ch_sync to ch2 */
712 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch2.control),
713 PLANB_SET(CH_SYNC));
714 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
715 PLANB_SET(DMA_ABORT));
717 base = (pb->frame_buffer_phys + pb->offset + pb->win.y * (pb->win.bpl
718 + pb->win.pad) + pb->win.x * bpp);
720 if (interlace) {
721 stepsize = 2;
722 jump = virt_to_bus(c1 + (nlines + 1) / 2);
723 } else {
724 stepsize = 1;
725 jump = virt_to_bus(c1 + nlines);
728 /* even field data: */
729 for (i=0; i < nlines; i += stepsize, c1++)
730 tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET,
731 count, base + i * (pb->win.bpl + pb->win.pad), jump);
733 /* For non-interlaced, we use even fields only */
734 if (!interlace)
735 goto cmd_tab_data_end;
737 /* Resync to odd field */
738 /* (2) wait for field sync to be set */
739 tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
740 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
741 PLANB_SET(ODD_FIELD));
742 /* wait for field sync to be cleared */
743 tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
744 /* if not odd field, wait until field sync is set again */
745 tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++;
746 /* assert ch_sync to ch2 */
747 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch2.control),
748 PLANB_SET(CH_SYNC));
749 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
750 PLANB_SET(DMA_ABORT));
752 /* odd field data: */
753 jump = virt_to_bus(c1 + nlines / 2);
754 for (i=1; i < nlines; i += stepsize, c1++)
755 tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count,
756 base + i * (pb->win.bpl + pb->win.pad), jump);
758 /* And jump back to the start */
759 cmd_tab_data_end:
760 pb->overlay_last1 = c1; /* keep a pointer to the last command */
761 tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->ch1_cmd));
763 /* Clipmask command buffer */
765 /* Preamble commands: */
766 tab_cmd_dbdma(c2++, DBDMA_NOP, 0);
767 tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.wait_sel),
768 PLANB_SET(CH_SYNC));
769 /* wait until ch1 asserts ch_sync */
770 tab_cmd_dbdma(c2++, DBDMA_NOP | WAIT_IFCLR, 0);
771 /* clear ch_sync asserted by ch1 */
772 tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.control),
773 PLANB_CLR(CH_SYNC));
774 tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.wait_sel),
775 PLANB_SET(FIELD_SYNC));
776 tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel),
777 PLANB_SET(ODD_FIELD));
779 /* jump to end of even field if appropriate */
780 /* this points to (interlace)? pos. C: pos. B */
781 jump = (interlace) ? virt_to_bus(c2 + (nlines + 1) / 2 + 2):
782 virt_to_bus(c2 + nlines + 2);
783 /* if odd field, skip over to odd field clipmasking */
784 tab_cmd_dbdma(c2++, DBDMA_NOP | BR_IFSET, jump);
786 /* even field mask: */
787 tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel),
788 PLANB_SET(DMA_ABORT));
789 /* this points to pos. B */
790 jump = (interlace) ? virt_to_bus(c2 + nlines + 1):
791 virt_to_bus(c2 + nlines);
792 base = virt_to_bus(pb->mask);
793 for (i=0; i < nlines; i += stepsize, c2++)
794 tab_cmd_gen(c2, OUTPUT_MORE | KEY_STREAM0 | BR_IFSET, 96,
795 base + i * 96, jump);
797 /* For non-interlaced, we use only even fields */
798 if(!interlace)
799 goto cmd_tab_mask_end;
801 /* odd field mask: */
802 /* C */ tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel),
803 PLANB_SET(DMA_ABORT));
804 /* this points to pos. B */
805 jump = virt_to_bus(c2 + nlines / 2);
806 base = virt_to_bus(pb->mask);
807 for (i=1; i < nlines; i += 2, c2++) /* abort if set */
808 tab_cmd_gen(c2, OUTPUT_MORE | KEY_STREAM0 | BR_IFSET, 96,
809 base + i * 96, jump);
811 /* Inform channel 1 and jump back to start */
812 cmd_tab_mask_end:
813 /* ok, I just realized this is kind of flawed. */
814 /* this part is reached only after odd field clipmasking. */
815 /* wanna clean up? */
816 /* wait for field sync to be set */
817 /* corresponds to fsync (1) of ch1 */
818 /* B */ tab_cmd_dbdma(c2++, DBDMA_NOP | WAIT_IFCLR, 0);
819 /* restart ch1, meant to clear any dead bit or something */
820 tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch1.control),
821 PLANB_CLR(RUN));
822 tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch1.control),
823 PLANB_SET(RUN));
824 pb->overlay_last2 = c2; /* keep a pointer to the last command */
825 /* start over even field clipmasking */
826 tab_cmd_dbdma(c2, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->ch2_cmd));
828 eieio();
829 return;
832 /*********************************/
833 /* grabdisplay support functions */
834 /*********************************/
836 static int palette2fmt[] = {
838 PLANB_GRAY,
842 PLANB_COLOUR32,
843 PLANB_COLOUR15,
854 #define PLANB_PALETTE_MAX 15
856 static inline int overlay_is_active(struct planb *pb)
858 unsigned int size = pb->tab_size * sizeof(struct dbdma_cmd);
859 unsigned int caddr = (unsigned)in_le32(&pb->planb_base->ch1.cmdptr);
861 return (in_le32(&pb->overlay_last1->cmd_dep) == pb->ch1_cmd_phys)
862 && (caddr < (pb->ch1_cmd_phys + size))
863 && (caddr >= (unsigned)pb->ch1_cmd_phys);
866 static int vgrab(struct planb *pb, struct video_mmap *mp)
868 unsigned int fr = mp->frame;
869 unsigned int format;
871 if(pb->rawbuf==NULL) {
872 int err;
873 if((err=grabbuf_alloc(pb)))
874 return err;
877 IDEBUG("PlanB: grab %d: %dx%d(%u)\n", pb->grabbing,
878 mp->width, mp->height, fr);
880 if(pb->grabbing >= MAX_GBUFFERS)
881 return -ENOBUFS;
882 if(fr > (MAX_GBUFFERS - 1) || fr < 0)
883 return -EINVAL;
884 if(mp->height <= 0 || mp->width <= 0)
885 return -EINVAL;
886 if(mp->format < 0 || mp->format >= PLANB_PALETTE_MAX)
887 return -EINVAL;
888 if((format = palette2fmt[mp->format]) == 0)
889 return -EINVAL;
890 if (mp->height * mp->width * format > PLANB_MAX_FBUF) /* format = bpp */
891 return -EINVAL;
893 planb_lock(pb);
894 if(mp->width != pb->gwidth[fr] || mp->height != pb->gheight[fr] ||
895 format != pb->gfmt[fr] || (pb->gnorm_switch[fr])) {
896 int i;
897 #ifndef PLANB_GSCANLINE
898 unsigned int osize = pb->gwidth[fr] * pb->gheight[fr]
899 * pb->gfmt[fr];
900 unsigned int nsize = mp->width * mp->height * format;
901 #endif
903 IDEBUG("PlanB: gwidth = %d, gheight = %d, mp->format = %u\n",
904 mp->width, mp->height, mp->format);
906 #ifndef PLANB_GSCANLINE
907 if(pb->gnorm_switch[fr])
908 nsize = 0;
909 if (nsize < osize) {
910 for(i = pb->gbuf_idx[fr]; osize > 0; i++) {
911 memset((void *)pb->rawbuf[i], 0, PAGE_SIZE);
912 osize -= PAGE_SIZE;
915 for(i = pb->l_fr_addr_idx[fr]; i < pb->l_fr_addr_idx[fr]
916 + pb->lnum[fr]; i++)
917 memset((void *)pb->rawbuf[i], 0, PAGE_SIZE);
918 #else
919 /* XXX TODO */
921 if(pb->gnorm_switch[fr])
922 memset((void *)pb->gbuffer[fr], 0,
923 pb->gbytes_per_line * pb->gheight[fr]);
924 else {
925 if(mp->
926 for(i = 0; i < pb->gheight[fr]; i++) {
927 memset((void *)(pb->gbuffer[fr]
928 + pb->gbytes_per_line * i
932 #endif
933 pb->gwidth[fr] = mp->width;
934 pb->gheight[fr] = mp->height;
935 pb->gfmt[fr] = format;
936 pb->last_cmd[fr] = setup_grab_cmd(fr, pb);
937 planb_pre_capture(fr, pb->gfmt[fr], pb); /* gfmt = bpp */
938 pb->need_pre_capture[fr] = 1;
939 pb->gnorm_switch[fr] = 0;
940 } else
941 pb->need_pre_capture[fr] = 0;
942 pb->frame_stat[fr] = GBUFFER_GRABBING;
943 if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) {
945 IDEBUG("PlanB: ch1 inactive, initiating grabbing\n");
947 planb_dbdma_stop(&pb->planb_base->ch1);
948 if(pb->need_pre_capture[fr]) {
950 IDEBUG("PlanB: padding pre-capture sequence\n");
952 out_le32 (&pb->planb_base->ch1.cmdptr,
953 virt_to_bus(pb->pre_cmd[fr]));
954 } else {
955 tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0);
956 tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0);
957 /* let's be on the safe side. here is not timing critical. */
958 tab_cmd_dbdma((pb->cap_cmd[fr] + 1), DBDMA_NOP, 0);
959 out_le32 (&pb->planb_base->ch1.cmdptr,
960 virt_to_bus(pb->cap_cmd[fr]));
962 planb_dbdma_restart(&pb->planb_base->ch1);
963 pb->last_fr = fr;
964 } else {
965 int i;
967 IDEBUG("PlanB: ch1 active, grabbing being queued\n");
969 if((pb->last_fr == -1) || ((pb->last_fr == -2) &&
970 overlay_is_active(pb))) {
972 IDEBUG("PlanB: overlay is active, grabbing defered\n");
974 tab_cmd_dbdma(pb->last_cmd[fr],
975 DBDMA_NOP | BR_ALWAYS,
976 virt_to_bus(pb->ch1_cmd));
977 if(pb->need_pre_capture[fr]) {
979 IDEBUG("PlanB: padding pre-capture sequence\n");
981 tab_cmd_store(pb->pre_cmd[fr],
982 virt_to_bus(&pb->overlay_last1->cmd_dep),
983 virt_to_bus(pb->ch1_cmd));
984 eieio();
985 out_le32 (&pb->overlay_last1->cmd_dep,
986 virt_to_bus(pb->pre_cmd[fr]));
987 } else {
988 tab_cmd_store(pb->cap_cmd[fr],
989 virt_to_bus(&pb->overlay_last1->cmd_dep),
990 virt_to_bus(pb->ch1_cmd));
991 tab_cmd_dbdma((pb->cap_cmd[fr] + 1),
992 DBDMA_NOP, 0);
993 eieio();
994 out_le32 (&pb->overlay_last1->cmd_dep,
995 virt_to_bus(pb->cap_cmd[fr]));
997 for(i = 0; overlay_is_active(pb) && i < 999; i++)
998 IDEBUG("PlanB: waiting for overlay done\n");
999 tab_cmd_dbdma(pb->ch1_cmd, DBDMA_NOP, 0);
1000 pb->prev_last_fr = fr;
1001 pb->last_fr = -2;
1002 } else if(pb->last_fr == -2) {
1004 IDEBUG("PlanB: mixed mode detected, grabbing"
1005 " will be done before activating overlay\n");
1007 tab_cmd_dbdma(pb->ch1_cmd, DBDMA_NOP, 0);
1008 if(pb->need_pre_capture[fr]) {
1010 IDEBUG("PlanB: padding pre-capture sequence\n");
1012 tab_cmd_dbdma(pb->last_cmd[pb->prev_last_fr],
1013 DBDMA_NOP | BR_ALWAYS,
1014 virt_to_bus(pb->pre_cmd[fr]));
1015 eieio();
1016 } else {
1017 tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0);
1018 if(pb->gwidth[pb->prev_last_fr] !=
1019 pb->gwidth[fr]
1020 || pb->gheight[pb->prev_last_fr] !=
1021 pb->gheight[fr]
1022 || pb->gfmt[pb->prev_last_fr] !=
1023 pb->gfmt[fr])
1024 tab_cmd_dbdma((pb->cap_cmd[fr] + 1),
1025 DBDMA_NOP, 0);
1026 else
1027 tab_cmd_dbdma((pb->cap_cmd[fr] + 1),
1028 DBDMA_NOP | BR_ALWAYS,
1029 virt_to_bus(pb->cap_cmd[fr] + 16));
1030 tab_cmd_dbdma(pb->last_cmd[pb->prev_last_fr],
1031 DBDMA_NOP | BR_ALWAYS,
1032 virt_to_bus(pb->cap_cmd[fr]));
1033 eieio();
1035 tab_cmd_dbdma(pb->last_cmd[fr],
1036 DBDMA_NOP | BR_ALWAYS,
1037 virt_to_bus(pb->ch1_cmd));
1038 eieio();
1039 pb->prev_last_fr = fr;
1040 pb->last_fr = -2;
1041 } else {
1043 IDEBUG("PlanB: active grabbing session detected\n");
1045 if(pb->need_pre_capture[fr]) {
1047 IDEBUG("PlanB: padding pre-capture sequence\n");
1049 tab_cmd_dbdma(pb->last_cmd[pb->last_fr],
1050 DBDMA_NOP | BR_ALWAYS,
1051 virt_to_bus(pb->pre_cmd[fr]));
1052 eieio();
1053 } else {
1054 tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0);
1055 tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0);
1056 if(pb->gwidth[pb->last_fr] != pb->gwidth[fr]
1057 || pb->gheight[pb->last_fr] !=
1058 pb->gheight[fr]
1059 || pb->gfmt[pb->last_fr] !=
1060 pb->gfmt[fr])
1061 tab_cmd_dbdma((pb->cap_cmd[fr] + 1),
1062 DBDMA_NOP, 0);
1063 else
1064 tab_cmd_dbdma((pb->cap_cmd[fr] + 1),
1065 DBDMA_NOP | BR_ALWAYS,
1066 virt_to_bus(pb->cap_cmd[fr] + 16));
1067 tab_cmd_dbdma(pb->last_cmd[pb->last_fr],
1068 DBDMA_NOP | BR_ALWAYS,
1069 virt_to_bus(pb->cap_cmd[fr]));
1070 eieio();
1072 pb->last_fr = fr;
1074 if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) {
1076 IDEBUG("PlanB: became inactive in the mean time..."
1077 "reactivating\n");
1079 planb_dbdma_stop(&pb->planb_base->ch1);
1080 out_le32 (&pb->planb_base->ch1.cmdptr,
1081 virt_to_bus(pb->cap_cmd[fr]));
1082 planb_dbdma_restart(&pb->planb_base->ch1);
1085 pb->grabbing++;
1086 planb_unlock(pb);
1088 return 0;
1091 static void planb_pre_capture(int fr, int bpp, struct planb *pb)
1093 volatile struct dbdma_cmd *c1 = pb->pre_cmd[fr];
1094 int interlace = (pb->gheight[fr] > pb->maxlines/2)? 1: 0;
1096 tab_cmd_dbdma(c1++, DBDMA_NOP, 0);
1097 if((c1 = cmd_geo_setup(c1, pb->gwidth[fr], pb->gheight[fr], interlace,
1098 bpp, 0, pb)) == NULL) {
1099 printk(KERN_WARNING "PlanB: encountered some problems\n");
1100 tab_cmd_dbdma(pb->pre_cmd[fr] + 1, DBDMA_STOP, 0);
1101 return;
1103 /* Sync to even field */
1104 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel),
1105 PLANB_SET(FIELD_SYNC));
1106 tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
1107 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
1108 PLANB_SET(ODD_FIELD));
1109 tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
1110 tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++;
1111 tab_cmd_dbdma(c1++, DBDMA_NOP | INTR_ALWAYS, 0);
1112 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
1113 PLANB_SET(DMA_ABORT));
1114 /* For non-interlaced, we use even fields only */
1115 if (pb->gheight[fr] <= pb->maxlines/2)
1116 goto cmd_tab_data_end;
1117 /* Sync to odd field */
1118 tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
1119 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
1120 PLANB_SET(ODD_FIELD));
1121 tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
1122 tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++;
1123 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
1124 PLANB_SET(DMA_ABORT));
1125 cmd_tab_data_end:
1126 tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->cap_cmd[fr]));
1128 eieio();
1131 static volatile struct dbdma_cmd *setup_grab_cmd(int fr, struct planb *pb)
1133 int i, bpp, count, nlines, stepsize, interlace;
1134 #ifdef PLANB_GSCANLINE
1135 int scanline;
1136 #else
1137 int nlpp, leftover1;
1138 unsigned long base;
1139 #endif
1140 unsigned long jump;
1141 int pagei;
1142 volatile struct dbdma_cmd *c1;
1143 volatile struct dbdma_cmd *jump_addr;
1145 c1 = pb->cap_cmd[fr];
1146 interlace = (pb->gheight[fr] > pb->maxlines/2)? 1: 0;
1147 bpp = pb->gfmt[fr]; /* gfmt = bpp */
1148 count = bpp * pb->gwidth[fr];
1149 nlines = pb->gheight[fr];
1150 #ifdef PLANB_GSCANLINE
1151 scanline = pb->gbytes_per_line;
1152 #else
1153 pb->lsize[fr] = count;
1154 pb->lnum[fr] = 0;
1155 #endif
1157 /* Do video in: */
1159 /* Preamble commands: */
1160 tab_cmd_dbdma(c1++, DBDMA_NOP, 0);
1161 tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(c1 + 16)); c1++;
1162 if((c1 = cmd_geo_setup(c1, pb->gwidth[fr], pb->gheight[fr], interlace,
1163 bpp, 0, pb)) == NULL) {
1164 printk(KERN_WARNING "PlanB: encountered serious problems\n");
1165 tab_cmd_dbdma(pb->cap_cmd[fr] + 1, DBDMA_STOP, 0);
1166 return (pb->cap_cmd[fr] + 2);
1168 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel),
1169 PLANB_SET(FIELD_SYNC));
1170 tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
1171 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
1172 PLANB_SET(ODD_FIELD));
1173 tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
1174 tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++;
1175 tab_cmd_dbdma(c1++, DBDMA_NOP | INTR_ALWAYS, 0);
1176 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
1177 PLANB_SET(DMA_ABORT));
1179 if (interlace) {
1180 stepsize = 2;
1181 jump_addr = c1 + TAB_FACTOR * (nlines + 1) / 2;
1182 } else {
1183 stepsize = 1;
1184 jump_addr = c1 + TAB_FACTOR * nlines;
1186 jump = virt_to_bus(jump_addr);
1188 /* even field data: */
1190 pagei = pb->gbuf_idx[fr];
1191 #ifdef PLANB_GSCANLINE
1192 for (i = 0; i < nlines; i += stepsize) {
1193 tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count,
1194 virt_to_bus(pb->rawbuf[pagei
1195 + i * scanline / PAGE_SIZE]), jump);
1197 #else
1198 i = 0;
1199 leftover1 = 0;
1200 do {
1201 int j;
1203 base = virt_to_bus(pb->rawbuf[pagei]);
1204 nlpp = (PAGE_SIZE - leftover1) / count / stepsize;
1205 for(j = 0; j < nlpp && i < nlines; j++, i += stepsize, c1++)
1206 tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET,
1207 count, base + count * j * stepsize + leftover1, jump);
1208 if(i < nlines) {
1209 int lov0 = PAGE_SIZE - count * nlpp * stepsize - leftover1;
1211 if(lov0 == 0)
1212 leftover1 = 0;
1213 else {
1214 if(lov0 >= count) {
1215 tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, base
1216 + count * nlpp * stepsize + leftover1, jump);
1217 } else {
1218 pb->l_to_addr[fr][pb->lnum[fr]] = pb->rawbuf[pagei]
1219 + count * nlpp * stepsize + leftover1;
1220 pb->l_to_next_idx[fr][pb->lnum[fr]] = pagei + 1;
1221 pb->l_to_next_size[fr][pb->lnum[fr]] = count - lov0;
1222 tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count,
1223 virt_to_bus(pb->rawbuf[pb->l_fr_addr_idx[fr]
1224 + pb->lnum[fr]]), jump);
1225 if(++pb->lnum[fr] > MAX_LNUM)
1226 pb->lnum[fr]--;
1228 leftover1 = count * stepsize - lov0;
1229 i += stepsize;
1232 pagei++;
1233 } while(i < nlines);
1234 tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, jump);
1235 c1 = jump_addr;
1236 #endif /* PLANB_GSCANLINE */
1238 /* For non-interlaced, we use even fields only */
1239 if (!interlace)
1240 goto cmd_tab_data_end;
1242 /* Sync to odd field */
1243 tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
1244 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
1245 PLANB_SET(ODD_FIELD));
1246 tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
1247 tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++;
1248 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
1249 PLANB_SET(DMA_ABORT));
1251 /* odd field data: */
1252 jump_addr = c1 + TAB_FACTOR * nlines / 2;
1253 jump = virt_to_bus(jump_addr);
1254 #ifdef PLANB_GSCANLINE
1255 for (i = 1; i < nlines; i += stepsize) {
1256 tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count,
1257 virt_to_bus(pb->rawbuf[pagei
1258 + i * scanline / PAGE_SIZE]), jump);
1260 #else
1261 i = 1;
1262 leftover1 = 0;
1263 pagei = pb->gbuf_idx[fr];
1264 if(nlines <= 1)
1265 goto skip;
1266 do {
1267 int j;
1269 base = virt_to_bus(pb->rawbuf[pagei]);
1270 nlpp = (PAGE_SIZE - leftover1) / count / stepsize;
1271 if(leftover1 >= count) {
1272 tab_cmd_gen(c1++, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count,
1273 base + leftover1 - count, jump);
1274 i += stepsize;
1276 for(j = 0; j < nlpp && i < nlines; j++, i += stepsize, c1++)
1277 tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count,
1278 base + count * (j * stepsize + 1) + leftover1, jump);
1279 if(i < nlines) {
1280 int lov0 = PAGE_SIZE - count * nlpp * stepsize - leftover1;
1282 if(lov0 == 0)
1283 leftover1 = 0;
1284 else {
1285 if(lov0 > count) {
1286 pb->l_to_addr[fr][pb->lnum[fr]] = pb->rawbuf[pagei]
1287 + count * (nlpp * stepsize + 1) + leftover1;
1288 pb->l_to_next_idx[fr][pb->lnum[fr]] = pagei + 1;
1289 pb->l_to_next_size[fr][pb->lnum[fr]] = count * stepsize
1290 - lov0;
1291 tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count,
1292 virt_to_bus(pb->rawbuf[pb->l_fr_addr_idx[fr]
1293 + pb->lnum[fr]]), jump);
1294 if(++pb->lnum[fr] > MAX_LNUM)
1295 pb->lnum[fr]--;
1296 i += stepsize;
1298 leftover1 = count * stepsize - lov0;
1301 pagei++;
1302 } while(i < nlines);
1303 skip:
1304 tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, jump);
1305 c1 = jump_addr;
1306 #endif /* PLANB_GSCANLINE */
1308 cmd_tab_data_end:
1309 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->intr_stat),
1310 (fr << 9) | PLANB_FRM_IRQ | PLANB_GEN_IRQ);
1311 /* stop it */
1312 tab_cmd_dbdma(c1, DBDMA_STOP, 0);
1314 eieio();
1315 return c1;
1318 static void planb_irq(int irq, void *dev_id, struct pt_regs * regs)
1320 unsigned int stat, astat;
1321 struct planb *pb = (struct planb *)dev_id;
1323 IDEBUG("PlanB: planb_irq()\n");
1325 /* get/clear interrupt status bits */
1326 eieio();
1327 stat = in_le32(&pb->planb_base->intr_stat);
1328 astat = stat & pb->intr_mask;
1329 out_le32(&pb->planb_base->intr_stat, PLANB_FRM_IRQ
1330 & ~astat & stat & ~PLANB_GEN_IRQ);
1331 IDEBUG("PlanB: stat = %X, astat = %X\n", stat, astat);
1333 if(astat & PLANB_FRM_IRQ) {
1334 unsigned int fr = stat >> 9;
1335 #ifndef PLANB_GSCANLINE
1336 int i;
1337 #endif
1338 IDEBUG("PlanB: PLANB_FRM_IRQ\n");
1340 pb->gcount++;
1342 IDEBUG("PlanB: grab %d: fr = %d, gcount = %d\n",
1343 pb->grabbing, fr, pb->gcount);
1344 #ifndef PLANB_GSCANLINE
1345 IDEBUG("PlanB: %d * %d bytes are being copied over\n",
1346 pb->lnum[fr], pb->lsize[fr]);
1347 for(i = 0; i < pb->lnum[fr]; i++) {
1348 int first = pb->lsize[fr] - pb->l_to_next_size[fr][i];
1350 memcpy(pb->l_to_addr[fr][i],
1351 pb->rawbuf[pb->l_fr_addr_idx[fr] + i],
1352 first);
1353 memcpy(pb->rawbuf[pb->l_to_next_idx[fr][i]],
1354 pb->rawbuf[pb->l_fr_addr_idx[fr] + i] + first,
1355 pb->l_to_next_size[fr][i]);
1357 #endif
1358 pb->frame_stat[fr] = GBUFFER_DONE;
1359 pb->grabbing--;
1360 wake_up_interruptible(&pb->capq);
1361 return;
1363 /* incorrect interrupts? */
1364 pb->intr_mask = PLANB_CLR_IRQ;
1365 out_le32(&pb->planb_base->intr_stat, PLANB_CLR_IRQ);
1366 printk(KERN_ERR "PlanB: IRQ lockup, cleared intrrupts"
1367 " unconditionally\n");
1370 /*******************************
1371 * Device Operations functions *
1372 *******************************/
1374 static int planb_open(struct video_device *dev, int mode)
1376 struct planb *pb = (struct planb *)dev;
1378 if (pb->user == 0) {
1379 int err;
1380 if((err = planb_prepare_open(pb)) != 0)
1381 return err;
1383 pb->user++;
1385 DEBUG("PlanB: device opened\n");
1386 return 0;
1389 static void planb_close(struct video_device *dev)
1391 struct planb *pb = (struct planb *)dev;
1393 if(pb->user < 1) /* ??? */
1394 return;
1395 planb_lock(pb);
1396 if (pb->user == 1) {
1397 if (pb->overlay) {
1398 planb_dbdma_stop(&pb->planb_base->ch2);
1399 planb_dbdma_stop(&pb->planb_base->ch1);
1400 pb->overlay = 0;
1402 planb_prepare_close(pb);
1404 pb->user--;
1405 planb_unlock(pb);
1407 DEBUG("PlanB: device closed\n");
1410 static long planb_read(struct video_device *v, char *buf, unsigned long count,
1411 int nonblock)
1413 DEBUG("planb: read request\n");
1414 return -EINVAL;
1417 static long planb_write(struct video_device *v, const char *buf,
1418 unsigned long count, int nonblock)
1420 DEBUG("planb: write request\n");
1421 return -EINVAL;
1424 static int planb_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
1426 struct planb *pb=(struct planb *)dev;
1428 switch (cmd)
1430 case VIDIOCGCAP:
1432 struct video_capability b;
1434 DEBUG("PlanB: IOCTL VIDIOCGCAP\n");
1436 strcpy (b.name, pb->video_dev.name);
1437 b.type = VID_TYPE_OVERLAY | VID_TYPE_CLIPPING |
1438 VID_TYPE_FRAMERAM | VID_TYPE_SCALES |
1439 VID_TYPE_CAPTURE;
1440 b.channels = 2; /* composite & svhs */
1441 b.audios = 0;
1442 b.maxwidth = PLANB_MAXPIXELS;
1443 b.maxheight = PLANB_MAXLINES;
1444 b.minwidth = 32; /* wild guess */
1445 b.minheight = 32;
1446 if (copy_to_user(arg,&b,sizeof(b)))
1447 return -EFAULT;
1448 return 0;
1450 case VIDIOCSFBUF:
1452 struct video_buffer v;
1453 unsigned short bpp;
1454 unsigned int fmt;
1456 DEBUG("PlanB: IOCTL VIDIOCSFBUF\n");
1458 if (!capable(CAP_SYS_ADMIN)
1459 || !capable(CAP_SYS_RAWIO))
1460 return -EPERM;
1461 if (copy_from_user(&v, arg,sizeof(v)))
1462 return -EFAULT;
1463 planb_lock(pb);
1464 switch(v.depth) {
1465 case 8:
1466 bpp = 1;
1467 fmt = PLANB_GRAY;
1468 break;
1469 case 15:
1470 case 16:
1471 bpp = 2;
1472 fmt = PLANB_COLOUR15;
1473 break;
1474 case 24:
1475 case 32:
1476 bpp = 4;
1477 fmt = PLANB_COLOUR32;
1478 break;
1479 default:
1480 planb_unlock(pb);
1481 return -EINVAL;
1483 if (bpp * v.width > v.bytesperline) {
1484 planb_unlock(pb);
1485 return -EINVAL;
1487 pb->win.bpp = bpp;
1488 pb->win.color_fmt = fmt;
1489 pb->frame_buffer_phys = (unsigned long) v.base;
1490 pb->win.sheight = v.height;
1491 pb->win.swidth = v.width;
1492 pb->picture.depth = pb->win.depth = v.depth;
1493 pb->win.bpl = pb->win.bpp * pb->win.swidth;
1494 pb->win.pad = v.bytesperline - pb->win.bpl;
1496 DEBUG("PlanB: Display at %p is %d by %d, bytedepth %d,"
1497 " bpl %d (+ %d)\n", v.base, v.width,v.height,
1498 pb->win.bpp, pb->win.bpl, pb->win.pad);
1500 pb->cmd_buff_inited = 0;
1501 if(pb->overlay) {
1502 suspend_overlay(pb);
1503 fill_cmd_buff(pb);
1504 resume_overlay(pb);
1506 planb_unlock(pb);
1507 return 0;
1509 case VIDIOCGFBUF:
1511 struct video_buffer v;
1513 DEBUG("PlanB: IOCTL VIDIOCGFBUF\n");
1515 v.base = (void *)pb->frame_buffer_phys;
1516 v.height = pb->win.sheight;
1517 v.width = pb->win.swidth;
1518 v.depth = pb->win.depth;
1519 v.bytesperline = pb->win.bpl + pb->win.pad;
1520 if (copy_to_user(arg, &v, sizeof(v)))
1521 return -EFAULT;
1522 return 0;
1524 case VIDIOCCAPTURE:
1526 int i;
1528 if(copy_from_user(&i, arg, sizeof(i)))
1529 return -EFAULT;
1530 if(i==0) {
1531 DEBUG("PlanB: IOCTL VIDIOCCAPTURE Stop\n");
1533 if (!(pb->overlay))
1534 return 0;
1535 planb_lock(pb);
1536 pb->overlay = 0;
1537 overlay_stop(pb);
1538 planb_unlock(pb);
1539 } else {
1540 DEBUG("PlanB: IOCTL VIDIOCCAPTURE Start\n");
1542 if (pb->frame_buffer_phys == 0 ||
1543 pb->win.width == 0 ||
1544 pb->win.height == 0)
1545 return -EINVAL;
1546 if (pb->overlay)
1547 return 0;
1548 planb_lock(pb);
1549 pb->overlay = 1;
1550 if(!(pb->cmd_buff_inited))
1551 fill_cmd_buff(pb);
1552 overlay_start(pb);
1553 planb_unlock(pb);
1555 return 0;
1557 case VIDIOCGCHAN:
1559 struct video_channel v;
1561 DEBUG("PlanB: IOCTL VIDIOCGCHAN\n");
1563 if(copy_from_user(&v, arg,sizeof(v)))
1564 return -EFAULT;
1565 v.flags = 0;
1566 v.tuners = 0;
1567 v.type = VIDEO_TYPE_CAMERA;
1568 v.norm = pb->win.norm;
1569 switch(v.channel)
1571 case 0:
1572 strcpy(v.name,"Composite");
1573 break;
1574 case 1:
1575 strcpy(v.name,"SVHS");
1576 break;
1577 default:
1578 return -EINVAL;
1579 break;
1581 if(copy_to_user(arg,&v,sizeof(v)))
1582 return -EFAULT;
1584 return 0;
1586 case VIDIOCSCHAN:
1588 struct video_channel v;
1590 DEBUG("PlanB: IOCTL VIDIOCSCHAN\n");
1592 if(copy_from_user(&v, arg, sizeof(v)))
1593 return -EFAULT;
1595 if (v.norm != pb->win.norm) {
1596 int i, maxlines;
1598 switch (v.norm)
1600 case VIDEO_MODE_PAL:
1601 case VIDEO_MODE_SECAM:
1602 maxlines = PLANB_MAXLINES;
1603 break;
1604 case VIDEO_MODE_NTSC:
1605 maxlines = PLANB_NTSC_MAXLINES;
1606 break;
1607 default:
1608 return -EINVAL;
1609 break;
1611 planb_lock(pb);
1612 /* empty the grabbing queue */
1613 while(pb->grabbing)
1614 interruptible_sleep_on(&pb->capq);
1615 pb->maxlines = maxlines;
1616 pb->win.norm = v.norm;
1617 /* Stop overlay if running */
1618 suspend_overlay(pb);
1619 for(i = 0; i < MAX_GBUFFERS; i++)
1620 pb->gnorm_switch[i] = 1;
1621 /* I know it's an overkill, but.... */
1622 fill_cmd_buff(pb);
1623 /* ok, now init it accordingly */
1624 saa_init_regs (pb);
1625 /* restart overlay if it was running */
1626 resume_overlay(pb);
1627 planb_unlock(pb);
1630 switch(v.channel)
1632 case 0: /* Composite */
1633 saa_set (SAA7196_IOCC,
1634 ((saa_regs[pb->win.norm][SAA7196_IOCC] &
1635 ~7) | 3), pb);
1636 break;
1637 case 1: /* SVHS */
1638 saa_set (SAA7196_IOCC,
1639 ((saa_regs[pb->win.norm][SAA7196_IOCC] &
1640 ~7) | 4), pb);
1641 break;
1642 default:
1643 return -EINVAL;
1644 break;
1647 return 0;
1649 case VIDIOCGPICT:
1651 struct video_picture vp = pb->picture;
1653 DEBUG("PlanB: IOCTL VIDIOCGPICT\n");
1655 switch(pb->win.color_fmt) {
1656 case PLANB_GRAY:
1657 vp.palette = VIDEO_PALETTE_GREY;
1658 case PLANB_COLOUR15:
1659 vp.palette = VIDEO_PALETTE_RGB555;
1660 break;
1661 case PLANB_COLOUR32:
1662 vp.palette = VIDEO_PALETTE_RGB32;
1663 break;
1664 default:
1665 vp.palette = 0;
1666 break;
1669 if(copy_to_user(arg,&vp,sizeof(vp)))
1670 return -EFAULT;
1671 return 0;
1673 case VIDIOCSPICT:
1675 struct video_picture vp;
1677 DEBUG("PlanB: IOCTL VIDIOCSPICT\n");
1679 if(copy_from_user(&vp,arg,sizeof(vp)))
1680 return -EFAULT;
1681 pb->picture = vp;
1682 /* Should we do sanity checks here? */
1683 saa_set (SAA7196_BRIG, (unsigned char)
1684 ((pb->picture.brightness) >> 8), pb);
1685 saa_set (SAA7196_HUEC, (unsigned char)
1686 ((pb->picture.hue) >> 8) ^ 0x80, pb);
1687 saa_set (SAA7196_CSAT, (unsigned char)
1688 ((pb->picture.colour) >> 9), pb);
1689 saa_set (SAA7196_CONT, (unsigned char)
1690 ((pb->picture.contrast) >> 9), pb);
1692 return 0;
1694 case VIDIOCSWIN:
1696 struct video_window vw;
1697 struct video_clip clip;
1698 int i;
1700 DEBUG("PlanB: IOCTL VIDIOCSWIN\n");
1702 if(copy_from_user(&vw,arg,sizeof(vw)))
1703 return -EFAULT;
1705 planb_lock(pb);
1706 /* Stop overlay if running */
1707 suspend_overlay(pb);
1708 pb->win.interlace = (vw.height > pb->maxlines/2)? 1: 0;
1709 if (pb->win.x != vw.x ||
1710 pb->win.y != vw.y ||
1711 pb->win.width != vw.width ||
1712 pb->win.height != vw.height ||
1713 !pb->cmd_buff_inited) {
1714 pb->win.x = vw.x;
1715 pb->win.y = vw.y;
1716 pb->win.width = vw.width;
1717 pb->win.height = vw.height;
1718 fill_cmd_buff(pb);
1720 /* Reset clip mask */
1721 memset ((void *) pb->mask, 0xff, (pb->maxlines
1722 * ((PLANB_MAXPIXELS + 7) & ~7)) / 8);
1723 /* Add any clip rects */
1724 for (i = 0; i < vw.clipcount; i++) {
1725 if (copy_from_user(&clip, vw.clips + i,
1726 sizeof(struct video_clip)))
1727 return -EFAULT;
1728 add_clip(pb, &clip);
1730 /* restart overlay if it was running */
1731 resume_overlay(pb);
1732 planb_unlock(pb);
1733 return 0;
1735 case VIDIOCGWIN:
1737 struct video_window vw;
1739 DEBUG("PlanB: IOCTL VIDIOCGWIN\n");
1741 vw.x=pb->win.x;
1742 vw.y=pb->win.y;
1743 vw.width=pb->win.width;
1744 vw.height=pb->win.height;
1745 vw.chromakey=0;
1746 vw.flags=0;
1747 if(pb->win.interlace)
1748 vw.flags|=VIDEO_WINDOW_INTERLACE;
1749 if(copy_to_user(arg,&vw,sizeof(vw)))
1750 return -EFAULT;
1751 return 0;
1753 case VIDIOCSYNC: {
1754 int i;
1756 IDEBUG("PlanB: IOCTL VIDIOCSYNC\n");
1758 if(copy_from_user((void *)&i,arg,sizeof(int)))
1759 return -EFAULT;
1761 IDEBUG("PlanB: sync to frame %d\n", i);
1763 if(i > (MAX_GBUFFERS - 1) || i < 0)
1764 return -EINVAL;
1765 chk_grab:
1766 switch (pb->frame_stat[i]) {
1767 case GBUFFER_UNUSED:
1768 return -EINVAL;
1769 case GBUFFER_GRABBING:
1770 IDEBUG("PlanB: waiting for grab"
1771 " done (%d)\n", i);
1772 interruptible_sleep_on(&pb->capq);
1773 if(signal_pending(current))
1774 return -EINTR;
1775 goto chk_grab;
1776 case GBUFFER_DONE:
1777 pb->frame_stat[i] = GBUFFER_UNUSED;
1778 break;
1780 return 0;
1783 case VIDIOCMCAPTURE:
1785 struct video_mmap vm;
1786 volatile unsigned int status;
1788 IDEBUG("PlanB: IOCTL VIDIOCMCAPTURE\n");
1790 if(copy_from_user((void *) &vm,(void *)arg,sizeof(vm)))
1791 return -EFAULT;
1792 status = pb->frame_stat[vm.frame];
1793 if (status != GBUFFER_UNUSED)
1794 return -EBUSY;
1796 return vgrab(pb, &vm);
1799 case VIDIOCGMBUF:
1801 int i;
1802 struct video_mbuf vm;
1804 DEBUG("PlanB: IOCTL VIDIOCGMBUF\n");
1806 memset(&vm, 0 , sizeof(vm));
1807 vm.size = PLANB_MAX_FBUF * MAX_GBUFFERS;
1808 vm.frames = MAX_GBUFFERS;
1809 for(i = 0; i<MAX_GBUFFERS; i++)
1810 vm.offsets[i] = PLANB_MAX_FBUF * i;
1811 if(copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
1812 return -EFAULT;
1813 return 0;
1816 case PLANBIOCGSAAREGS:
1818 struct planb_saa_regs preg;
1820 DEBUG("PlanB: IOCTL PLANBIOCGSAAREGS\n");
1822 if(copy_from_user(&preg, arg, sizeof(preg)))
1823 return -EFAULT;
1824 if(preg.addr >= SAA7196_NUMREGS)
1825 return -EINVAL;
1826 preg.val = saa_regs[pb->win.norm][preg.addr];
1827 if(copy_to_user((void *)arg, (void *)&preg,
1828 sizeof(preg)))
1829 return -EFAULT;
1830 return 0;
1833 case PLANBIOCSSAAREGS:
1835 struct planb_saa_regs preg;
1837 DEBUG("PlanB: IOCTL PLANBIOCSSAAREGS\n");
1839 if(copy_from_user(&preg, arg, sizeof(preg)))
1840 return -EFAULT;
1841 if(preg.addr >= SAA7196_NUMREGS)
1842 return -EINVAL;
1843 saa_set (preg.addr, preg.val, pb);
1844 return 0;
1847 case PLANBIOCGSTAT:
1849 struct planb_stat_regs pstat;
1851 DEBUG("PlanB: IOCTL PLANBIOCGSTAT\n");
1853 pstat.ch1_stat = in_le32(&pb->planb_base->ch1.status);
1854 pstat.ch2_stat = in_le32(&pb->planb_base->ch2.status);
1855 pstat.saa_stat0 = saa_status(0, pb);
1856 pstat.saa_stat1 = saa_status(1, pb);
1858 if(copy_to_user((void *)arg, (void *)&pstat,
1859 sizeof(pstat)))
1860 return -EFAULT;
1861 return 0;
1864 case PLANBIOCSMODE: {
1865 int v;
1867 DEBUG("PlanB: IOCTL PLANBIOCSMODE\n");
1869 if(copy_from_user(&v, arg, sizeof(v)))
1870 return -EFAULT;
1872 switch(v)
1874 case PLANB_TV_MODE:
1875 saa_set (SAA7196_STDC,
1876 (saa_regs[pb->win.norm][SAA7196_STDC] &
1877 0x7f), pb);
1878 break;
1879 case PLANB_VTR_MODE:
1880 saa_set (SAA7196_STDC,
1881 (saa_regs[pb->win.norm][SAA7196_STDC] |
1882 0x80), pb);
1883 break;
1884 default:
1885 return -EINVAL;
1886 break;
1888 pb->win.mode = v;
1889 return 0;
1891 case PLANBIOCGMODE: {
1892 int v=pb->win.mode;
1894 DEBUG("PlanB: IOCTL PLANBIOCGMODE\n");
1896 if(copy_to_user(arg,&v,sizeof(v)))
1897 return -EFAULT;
1898 return 0;
1900 #ifdef PLANB_GSCANLINE
1901 case PLANBG_GRAB_BPL: {
1902 int v=pb->gbytes_per_line;
1904 DEBUG("PlanB: IOCTL PLANBG_GRAB_BPL\n");
1906 if(copy_to_user(arg,&v,sizeof(v)))
1907 return -EFAULT;
1908 return 0;
1910 #endif /* PLANB_GSCANLINE */
1911 case PLANB_INTR_DEBUG: {
1912 int i;
1914 DEBUG("PlanB: IOCTL PLANB_INTR_DEBUG\n");
1916 if(copy_from_user(&i, arg, sizeof(i)))
1917 return -EFAULT;
1919 /* avoid hang ups all together */
1920 for (i = 0; i < MAX_GBUFFERS; i++) {
1921 if(pb->frame_stat[i] == GBUFFER_GRABBING) {
1922 pb->frame_stat[i] = GBUFFER_DONE;
1925 if(pb->grabbing)
1926 pb->grabbing--;
1927 wake_up_interruptible(&pb->capq);
1928 return 0;
1930 case PLANB_INV_REGS: {
1931 int i;
1932 struct planb_any_regs any;
1934 DEBUG("PlanB: IOCTL PLANB_INV_REGS\n");
1936 if(copy_from_user(&any, arg, sizeof(any)))
1937 return -EFAULT;
1938 if(any.offset < 0 || any.offset + any.bytes > 0x400)
1939 return -EINVAL;
1940 if(any.bytes > 128)
1941 return -EINVAL;
1942 for (i = 0; i < any.bytes; i++) {
1943 any.data[i] =
1944 in_8((unsigned char *)pb->planb_base
1945 + any.offset + i);
1947 if(copy_to_user(arg,&any,sizeof(any)))
1948 return -EFAULT;
1949 return 0;
1951 default:
1953 DEBUG("PlanB: Unimplemented IOCTL\n");
1954 return -ENOIOCTLCMD;
1956 /* Some IOCTLs are currently unsupported on PlanB */
1957 case VIDIOCGTUNER: {
1958 DEBUG("PlanB: IOCTL VIDIOCGTUNER\n");
1959 goto unimplemented; }
1960 case VIDIOCSTUNER: {
1961 DEBUG("PlanB: IOCTL VIDIOCSTUNER\n");
1962 goto unimplemented; }
1963 case VIDIOCSFREQ: {
1964 DEBUG("PlanB: IOCTL VIDIOCSFREQ\n");
1965 goto unimplemented; }
1966 case VIDIOCGFREQ: {
1967 DEBUG("PlanB: IOCTL VIDIOCGFREQ\n");
1968 goto unimplemented; }
1969 case VIDIOCKEY: {
1970 DEBUG("PlanB: IOCTL VIDIOCKEY\n");
1971 goto unimplemented; }
1972 case VIDIOCSAUDIO: {
1973 DEBUG("PlanB: IOCTL VIDIOCSAUDIO\n");
1974 goto unimplemented; }
1975 case VIDIOCGAUDIO: {
1976 DEBUG("PlanB: IOCTL VIDIOCGAUDIO\n");
1977 goto unimplemented; }
1978 unimplemented:
1979 DEBUG(" Unimplemented\n");
1980 return -ENOIOCTLCMD;
1982 return 0;
1985 static int planb_mmap(struct vm_area_struct *vma, struct video_device *dev, const char *adr, unsigned long size)
1987 int i;
1988 struct planb *pb = (struct planb *)dev;
1989 unsigned long start = (unsigned long)adr;
1991 if (size > MAX_GBUFFERS * PLANB_MAX_FBUF)
1992 return -EINVAL;
1993 if (!pb->rawbuf) {
1994 int err;
1995 if((err=grabbuf_alloc(pb)))
1996 return err;
1998 for (i = 0; i < pb->rawbuf_size; i++) {
1999 if (remap_page_range(vma, start, virt_to_phys((void *)pb->rawbuf[i]),
2000 PAGE_SIZE, PAGE_SHARED))
2001 return -EAGAIN;
2002 start += PAGE_SIZE;
2003 if (size <= PAGE_SIZE)
2004 break;
2005 size -= PAGE_SIZE;
2007 return 0;
2010 static struct video_device planb_template=
2012 .owner = THIS_MODULE,
2013 .name = PLANB_DEVICE_NAME,
2014 .type = VID_TYPE_OVERLAY,
2015 .hardware = VID_HARDWARE_PLANB,
2016 .open = planb_open,
2017 .close = planb_close,
2018 .read = planb_read,
2019 .write = planb_write,
2020 .ioctl = planb_ioctl,
2021 .mmap = planb_mmap, /* mmap? */
2024 static int init_planb(struct planb *pb)
2026 unsigned char saa_rev;
2027 int i, result;
2029 memset ((void *) &pb->win, 0, sizeof (struct planb_window));
2030 /* Simple sanity check */
2031 if(def_norm >= NUM_SUPPORTED_NORM || def_norm < 0) {
2032 printk(KERN_ERR "PlanB: Option(s) invalid\n");
2033 return -2;
2035 pb->win.norm = def_norm;
2036 pb->win.mode = PLANB_TV_MODE; /* TV mode */
2037 pb->win.interlace=1;
2038 pb->win.x=0;
2039 pb->win.y=0;
2040 pb->win.width=768; /* 640 */
2041 pb->win.height=576; /* 480 */
2042 pb->maxlines=576;
2043 #if 0
2044 btv->win.cropwidth=768; /* 640 */
2045 btv->win.cropheight=576; /* 480 */
2046 btv->win.cropx=0;
2047 btv->win.cropy=0;
2048 #endif
2049 pb->win.pad=0;
2050 pb->win.bpp=4;
2051 pb->win.depth=32;
2052 pb->win.color_fmt=PLANB_COLOUR32;
2053 pb->win.bpl=1024*pb->win.bpp;
2054 pb->win.swidth=1024;
2055 pb->win.sheight=768;
2056 #ifdef PLANB_GSCANLINE
2057 if((pb->gbytes_per_line = PLANB_MAXPIXELS * 4) > PAGE_SIZE
2058 || (pb->gbytes_per_line <= 0))
2059 return -3;
2060 else {
2061 /* page align pb->gbytes_per_line for DMA purpose */
2062 for(i = PAGE_SIZE; pb->gbytes_per_line < (i>>1);)
2063 i>>=1;
2064 pb->gbytes_per_line = i;
2066 #endif
2067 pb->tab_size = PLANB_MAXLINES + 40;
2068 pb->suspend = 0;
2069 init_MUTEX(&pb->lock);
2070 pb->ch1_cmd = 0;
2071 pb->ch2_cmd = 0;
2072 pb->mask = 0;
2073 pb->priv_space = 0;
2074 pb->offset = 0;
2075 pb->user = 0;
2076 pb->overlay = 0;
2077 init_waitqueue_head(&pb->suspendq);
2078 pb->cmd_buff_inited = 0;
2079 pb->frame_buffer_phys = 0;
2081 /* Reset DMA controllers */
2082 planb_dbdma_stop(&pb->planb_base->ch2);
2083 planb_dbdma_stop(&pb->planb_base->ch1);
2085 saa_rev = (saa_status(0, pb) & 0xf0) >> 4;
2086 printk(KERN_INFO "PlanB: SAA7196 video processor rev. %d\n", saa_rev);
2087 /* Initialize the SAA registers in memory and on chip */
2088 saa_init_regs (pb);
2090 /* clear interrupt mask */
2091 pb->intr_mask = PLANB_CLR_IRQ;
2093 result = request_irq(pb->irq, planb_irq, 0, "PlanB", (void *)pb);
2094 if (result < 0) {
2095 if (result==-EINVAL)
2096 printk(KERN_ERR "PlanB: Bad irq number (%d) "
2097 "or handler\n", (int)pb->irq);
2098 else if (result==-EBUSY)
2099 printk(KERN_ERR "PlanB: I don't know why, "
2100 "but IRQ %d is busy\n", (int)pb->irq);
2101 return result;
2103 disable_irq(pb->irq);
2105 /* Now add the template and register the device unit. */
2106 memcpy(&pb->video_dev,&planb_template,sizeof(planb_template));
2108 pb->picture.brightness=0x90<<8;
2109 pb->picture.contrast = 0x70 << 8;
2110 pb->picture.colour = 0x70<<8;
2111 pb->picture.hue = 0x8000;
2112 pb->picture.whiteness = 0;
2113 pb->picture.depth = pb->win.depth;
2115 pb->frame_stat=NULL;
2116 init_waitqueue_head(&pb->capq);
2117 for(i=0; i<MAX_GBUFFERS; i++) {
2118 pb->gbuf_idx[i] = PLANB_MAX_FBUF * i / PAGE_SIZE;
2119 pb->gwidth[i]=0;
2120 pb->gheight[i]=0;
2121 pb->gfmt[i]=0;
2122 pb->cap_cmd[i]=NULL;
2123 #ifndef PLANB_GSCANLINE
2124 pb->l_fr_addr_idx[i] = MAX_GBUFFERS * (PLANB_MAX_FBUF
2125 / PAGE_SIZE + 1) + MAX_LNUM * i;
2126 pb->lsize[i] = 0;
2127 pb->lnum[i] = 0;
2128 #endif
2130 pb->rawbuf=NULL;
2131 pb->grabbing=0;
2133 /* enable interrupts */
2134 out_le32(&pb->planb_base->intr_stat, PLANB_CLR_IRQ);
2135 pb->intr_mask = PLANB_FRM_IRQ;
2136 enable_irq(pb->irq);
2138 if(video_register_device(&pb->video_dev, VFL_TYPE_GRABBER, video_nr)<0)
2139 return -1;
2141 return 0;
2145 * Scan for a PlanB controller, request the irq and map the io memory
2148 static int find_planb(void)
2150 struct planb *pb;
2151 struct device_node *planb_devices;
2152 unsigned char dev_fn, confreg, bus;
2153 unsigned int old_base, new_base;
2154 unsigned int irq;
2155 struct pci_dev *pdev;
2156 int rc;
2158 if (_machine != _MACH_Pmac)
2159 return 0;
2161 planb_devices = find_devices("planb");
2162 if (planb_devices == 0) {
2163 planb_num=0;
2164 printk(KERN_WARNING "PlanB: no device found!\n");
2165 return planb_num;
2168 if (planb_devices->next != NULL)
2169 printk(KERN_ERR "Warning: only using first PlanB device!\n");
2170 pb = &planbs[0];
2171 planb_num = 1;
2173 if (planb_devices->n_addrs != 1) {
2174 printk (KERN_WARNING "PlanB: expecting 1 address for planb "
2175 "(got %d)", planb_devices->n_addrs);
2176 return 0;
2179 if (planb_devices->n_intrs == 0) {
2180 printk(KERN_WARNING "PlanB: no intrs for device %s\n",
2181 planb_devices->full_name);
2182 return 0;
2183 } else {
2184 irq = planb_devices->intrs[0].line;
2187 /* Initialize PlanB's PCI registers */
2189 /* There is a bug with the way OF assigns addresses
2190 to the devices behind the chaos bridge.
2191 control needs only 0x1000 of space, but decodes only
2192 the upper 16 bits. It therefore occupies a full 64K.
2193 OF assigns the planb controller memory within this space;
2194 so we need to change that here in order to access planb. */
2196 /* We remap to 0xf1000000 in hope that nobody uses it ! */
2198 bus = (planb_devices->addrs[0].space >> 16) & 0xff;
2199 dev_fn = (planb_devices->addrs[0].space >> 8) & 0xff;
2200 confreg = planb_devices->addrs[0].space & 0xff;
2201 old_base = planb_devices->addrs[0].address;
2202 new_base = 0xf1000000;
2204 DEBUG("PlanB: Found on bus %d, dev %d, func %d, "
2205 "membase 0x%x (base reg. 0x%x)\n",
2206 bus, PCI_SLOT(dev_fn), PCI_FUNC(dev_fn), old_base, confreg);
2208 pdev = pci_find_slot (bus, dev_fn);
2209 if (!pdev) {
2210 printk(KERN_ERR "planb: cannot find slot\n");
2211 goto err_out;
2214 /* Enable response in memory space, bus mastering,
2215 use memory write and invalidate */
2216 rc = pci_enable_device(pdev);
2217 if (rc) {
2218 printk(KERN_ERR "planb: cannot enable PCI device %s\n",
2219 pci_name(pdev));
2220 goto err_out;
2222 rc = pci_set_mwi(pdev);
2223 if (rc) {
2224 printk(KERN_ERR "planb: cannot enable MWI on PCI device %s\n",
2225 pci_name(pdev));
2226 goto err_out_disable;
2228 pci_set_master(pdev);
2230 /* Set the new base address */
2231 pci_write_config_dword (pdev, confreg, new_base);
2233 planb_regs = (volatile struct planb_registers *)
2234 ioremap (new_base, 0x400);
2235 pb->planb_base = planb_regs;
2236 pb->planb_base_phys = (struct planb_registers *)new_base;
2237 pb->irq = irq;
2239 return planb_num;
2241 err_out_disable:
2242 pci_disable_device(pdev);
2243 err_out:
2244 /* FIXME handle error */ /* comment moved from pci_find_slot, above */
2245 return 0;
2248 static void release_planb(void)
2250 int i;
2251 struct planb *pb;
2253 for (i=0;i<planb_num; i++)
2255 pb=&planbs[i];
2257 /* stop and flash DMAs unconditionally */
2258 planb_dbdma_stop(&pb->planb_base->ch2);
2259 planb_dbdma_stop(&pb->planb_base->ch1);
2261 /* clear and free interrupts */
2262 pb->intr_mask = PLANB_CLR_IRQ;
2263 out_le32 (&pb->planb_base->intr_stat, PLANB_CLR_IRQ);
2264 free_irq(pb->irq, pb);
2266 /* make sure all allocated memory are freed */
2267 planb_prepare_close(pb);
2269 printk(KERN_INFO "PlanB: unregistering with v4l\n");
2270 video_unregister_device(&pb->video_dev);
2272 /* note that iounmap() does nothing on the PPC right now */
2273 iounmap ((void *)pb->planb_base);
2277 static int __init init_planbs(void)
2279 int i;
2281 if (find_planb()<=0)
2282 return -EIO;
2284 for (i=0; i<planb_num; i++) {
2285 if (init_planb(&planbs[i])<0) {
2286 printk(KERN_ERR "PlanB: error registering device %d"
2287 " with v4l\n", i);
2288 release_planb();
2289 return -EIO;
2291 printk(KERN_INFO "PlanB: registered device %d with v4l\n", i);
2293 return 0;
2296 static void __exit exit_planbs(void)
2298 release_planb();
2301 module_init(init_planbs);
2302 module_exit(exit_planbs);