DM9000: Fix endian-ness of data accesses.
[linux-2.6/zen-sources.git] / drivers / media / video / planb.c
blob36047d4e70f625d1fa693e210c60eebbb9d20fc8
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 <media/v4l2-common.h>
44 #include <linux/wait.h>
45 #include <asm/uaccess.h>
46 #include <asm/io.h>
47 #include <asm/prom.h>
48 #include <asm/dbdma.h>
49 #include <asm/pgtable.h>
50 #include <asm/page.h>
51 #include <asm/irq.h>
52 #include <linux/mutex.h>
54 #include "planb.h"
55 #include "saa7196.h"
57 /* Would you mind for some ugly debugging? */
58 #if 0
59 #define DEBUG(x...) printk(KERN_DEBUG ## x) /* Debug driver */
60 #else
61 #define DEBUG(x...) /* Don't debug driver */
62 #endif
64 #if 0
65 #define IDEBUG(x...) printk(KERN_DEBUG ## x) /* Debug interrupt part */
66 #else
67 #define IDEBUG(x...) /* Don't debug interrupt part */
68 #endif
70 /* Ever seen a Mac with more than 1 of these? */
71 #define PLANB_MAX 1
73 static int planb_num;
74 static struct planb planbs[PLANB_MAX];
75 static volatile struct planb_registers *planb_regs;
77 static int def_norm = PLANB_DEF_NORM; /* default norm */
78 static int video_nr = -1;
80 module_param(def_norm, int, 0);
81 MODULE_PARM_DESC(def_norm, "Default startup norm (0=PAL, 1=NTSC, 2=SECAM)");
82 module_param(video_nr, int, 0);
83 MODULE_LICENSE("GPL");
86 /* ------------------ PlanB Exported Functions ------------------ */
87 static long planb_write(struct video_device *, const char *, unsigned long, int);
88 static long planb_read(struct video_device *, char *, unsigned long, int);
89 static int planb_open(struct video_device *, int);
90 static void planb_close(struct video_device *);
91 static int planb_ioctl(struct video_device *, unsigned int, void *);
92 static int planb_init_done(struct video_device *);
93 static int planb_mmap(struct video_device *, const char *, unsigned long);
94 static void release_planb(void);
95 int init_planbs(struct video_init *);
97 /* ------------------ PlanB Internal Functions ------------------ */
98 static int planb_prepare_open(struct planb *);
99 static void planb_prepare_close(struct planb *);
100 static void saa_write_reg(unsigned char, unsigned char);
101 static unsigned char saa_status(int, struct planb *);
102 static void saa_set(unsigned char, unsigned char, struct planb *);
103 static void saa_init_regs(struct planb *);
104 static int grabbuf_alloc(struct planb *);
105 static int vgrab(struct planb *, struct video_mmap *);
106 static void add_clip(struct planb *, struct video_clip *);
107 static void fill_cmd_buff(struct planb *);
108 static void cmd_buff(struct planb *);
109 static volatile struct dbdma_cmd *setup_grab_cmd(int, struct planb *);
110 static void overlay_start(struct planb *);
111 static void overlay_stop(struct planb *);
112 static inline void tab_cmd_dbdma(volatile struct dbdma_cmd *, unsigned short,
113 unsigned int);
114 static inline void tab_cmd_store(volatile struct dbdma_cmd *, unsigned int,
115 unsigned int);
116 static inline void tab_cmd_gen(volatile struct dbdma_cmd *, unsigned short,
117 unsigned short, unsigned int, unsigned int);
118 static int init_planb(struct planb *);
119 static int find_planb(void);
120 static void planb_pre_capture(int, int, struct planb *);
121 static volatile struct dbdma_cmd *cmd_geo_setup(volatile struct dbdma_cmd *,
122 int, int, int, int, int, struct planb *);
123 static inline void planb_dbdma_stop(volatile struct dbdma_regs *);
124 static unsigned int saa_geo_setup(int, int, int, int, struct planb *);
125 static inline int overlay_is_active(struct planb *);
127 /*******************************/
128 /* Memory management functions */
129 /*******************************/
131 static int grabbuf_alloc(struct planb *pb)
133 int i, npage;
135 npage = MAX_GBUFFERS * ((PLANB_MAX_FBUF / PAGE_SIZE + 1)
136 #ifndef PLANB_GSCANLINE
137 + MAX_LNUM
138 #endif /* PLANB_GSCANLINE */
140 if ((pb->rawbuf = kmalloc(npage
141 * sizeof(unsigned long), GFP_KERNEL)) == 0)
142 return -ENOMEM;
143 for (i = 0; i < npage; i++) {
144 pb->rawbuf[i] = (unsigned char *)__get_free_pages(GFP_KERNEL
145 |GFP_DMA, 0);
146 if (!pb->rawbuf[i])
147 break;
148 SetPageReserved(virt_to_page(pb->rawbuf[i]));
150 if (i-- < npage) {
151 printk(KERN_DEBUG "PlanB: init_grab: grab buffer not allocated\n");
152 for (; i > 0; i--) {
153 ClearPageReserved(virt_to_page(pb->rawbuf[i]));
154 free_pages((unsigned long)pb->rawbuf[i], 0);
156 kfree(pb->rawbuf);
157 return -ENOBUFS;
159 pb->rawbuf_size = npage;
160 return 0;
163 /*****************************/
164 /* Hardware access functions */
165 /*****************************/
167 static void saa_write_reg(unsigned char addr, unsigned char val)
169 planb_regs->saa_addr = addr; eieio();
170 planb_regs->saa_regval = val; eieio();
171 return;
174 /* return status byte 0 or 1: */
175 static unsigned char saa_status(int byte, struct planb *pb)
177 saa_regs[pb->win.norm][SAA7196_STDC] =
178 (saa_regs[pb->win.norm][SAA7196_STDC] & ~2) | ((byte & 1) << 1);
179 saa_write_reg (SAA7196_STDC, saa_regs[pb->win.norm][SAA7196_STDC]);
181 /* Let's wait 30msec for this one */
182 msleep_interruptible(30);
184 return (unsigned char)in_8 (&planb_regs->saa_status);
187 static void saa_set(unsigned char addr, unsigned char val, struct planb *pb)
189 if(saa_regs[pb->win.norm][addr] != val) {
190 saa_regs[pb->win.norm][addr] = val;
191 saa_write_reg (addr, val);
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 mutex_lock(&pb->lock);
335 static inline void planb_unlock(struct planb *pb)
337 mutex_unlock(&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 = kzalloc (size, GFP_KERNEL)) == 0)
356 return -ENOMEM;
357 pb->overlay_last1 = pb->ch1_cmd = (volatile struct dbdma_cmd *)
358 DBDMA_ALIGN (pb->priv_space);
359 pb->overlay_last2 = pb->ch2_cmd = pb->ch1_cmd + pb->tab_size;
360 pb->ch1_cmd_phys = virt_to_bus(pb->ch1_cmd);
361 pb->cap_cmd[0] = pb->ch2_cmd + pb->tab_size;
362 pb->pre_cmd[0] = pb->cap_cmd[0] + pb->tab_size * TAB_FACTOR;
363 for (i = 1; i < MAX_GBUFFERS; i++) {
364 pb->cap_cmd[i] = pb->pre_cmd[i-1] + PLANB_DUMMY;
365 pb->pre_cmd[i] = pb->cap_cmd[i] + pb->tab_size * TAB_FACTOR;
367 pb->frame_stat=(volatile unsigned int *)(pb->pre_cmd[MAX_GBUFFERS-1]
368 + PLANB_DUMMY);
369 pb->mask = (unsigned char *)(pb->frame_stat+MAX_GBUFFERS);
371 pb->rawbuf = NULL;
372 pb->rawbuf_size = 0;
373 pb->grabbing = 0;
374 for (i = 0; i < MAX_GBUFFERS; i++) {
375 pb->frame_stat[i] = GBUFFER_UNUSED;
376 pb->gwidth[i] = 0;
377 pb->gheight[i] = 0;
378 pb->gfmt[i] = 0;
379 pb->gnorm_switch[i] = 0;
380 #ifndef PLANB_GSCANLINE
381 pb->lsize[i] = 0;
382 pb->lnum[i] = 0;
383 #endif /* PLANB_GSCANLINE */
385 pb->gcount = 0;
386 pb->suspend = 0;
387 pb->last_fr = -999;
388 pb->prev_last_fr = -999;
390 /* Reset DMA controllers */
391 planb_dbdma_stop(&pb->planb_base->ch2);
392 planb_dbdma_stop(&pb->planb_base->ch1);
394 return 0;
397 static void planb_prepare_close(struct planb *pb)
399 int i;
401 /* make sure the dma's are idle */
402 planb_dbdma_stop(&pb->planb_base->ch2);
403 planb_dbdma_stop(&pb->planb_base->ch1);
404 /* free kernel memory of command buffers */
405 if(pb->priv_space != 0) {
406 kfree (pb->priv_space);
407 pb->priv_space = 0;
408 pb->cmd_buff_inited = 0;
410 if(pb->rawbuf) {
411 for (i = 0; i < pb->rawbuf_size; i++) {
412 ClearPageReserved(virt_to_page(pb->rawbuf[i]));
413 free_pages((unsigned long)pb->rawbuf[i], 0);
415 kfree(pb->rawbuf);
417 pb->rawbuf = NULL;
420 /*****************************/
421 /* overlay support functions */
422 /*****************************/
424 static inline int overlay_is_active(struct planb *pb)
426 unsigned int size = pb->tab_size * sizeof(struct dbdma_cmd);
427 unsigned int caddr = (unsigned)in_le32(&pb->planb_base->ch1.cmdptr);
429 return (in_le32(&pb->overlay_last1->cmd_dep) == pb->ch1_cmd_phys)
430 && (caddr < (pb->ch1_cmd_phys + size))
431 && (caddr >= (unsigned)pb->ch1_cmd_phys);
434 static void overlay_start(struct planb *pb)
437 DEBUG("PlanB: overlay_start()\n");
439 if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) {
441 DEBUG("PlanB: presumably, grabbing is in progress...\n");
443 planb_dbdma_stop(&pb->planb_base->ch2);
444 out_le32 (&pb->planb_base->ch2.cmdptr,
445 virt_to_bus(pb->ch2_cmd));
446 planb_dbdma_restart(&pb->planb_base->ch2);
447 st_le16 (&pb->ch1_cmd->command, DBDMA_NOP);
448 tab_cmd_dbdma(pb->last_cmd[pb->last_fr],
449 DBDMA_NOP | BR_ALWAYS,
450 virt_to_bus(pb->ch1_cmd));
451 eieio();
452 pb->prev_last_fr = pb->last_fr;
453 pb->last_fr = -2;
454 if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) {
455 IDEBUG("PlanB: became inactive "
456 "in the mean time... reactivating\n");
457 planb_dbdma_stop(&pb->planb_base->ch1);
458 out_le32 (&pb->planb_base->ch1.cmdptr,
459 virt_to_bus(pb->ch1_cmd));
460 planb_dbdma_restart(&pb->planb_base->ch1);
462 } else {
464 DEBUG("PlanB: currently idle, so can do whatever\n");
466 planb_dbdma_stop(&pb->planb_base->ch2);
467 planb_dbdma_stop(&pb->planb_base->ch1);
468 st_le32 (&pb->planb_base->ch2.cmdptr,
469 virt_to_bus(pb->ch2_cmd));
470 st_le32 (&pb->planb_base->ch1.cmdptr,
471 virt_to_bus(pb->ch1_cmd));
472 out_le16 (&pb->ch1_cmd->command, DBDMA_NOP);
473 planb_dbdma_restart(&pb->planb_base->ch2);
474 planb_dbdma_restart(&pb->planb_base->ch1);
475 pb->last_fr = -1;
477 return;
480 static void overlay_stop(struct planb *pb)
482 DEBUG("PlanB: overlay_stop()\n");
484 if(pb->last_fr == -1) {
486 DEBUG("PlanB: no grabbing, it seems...\n");
488 planb_dbdma_stop(&pb->planb_base->ch2);
489 planb_dbdma_stop(&pb->planb_base->ch1);
490 pb->last_fr = -999;
491 } else if(pb->last_fr == -2) {
492 unsigned int cmd_dep;
493 tab_cmd_dbdma(pb->cap_cmd[pb->prev_last_fr], DBDMA_STOP, 0);
494 eieio();
495 cmd_dep = (unsigned int)in_le32(&pb->overlay_last1->cmd_dep);
496 if(overlay_is_active(pb)) {
498 DEBUG("PlanB: overlay is currently active\n");
500 planb_dbdma_stop(&pb->planb_base->ch2);
501 planb_dbdma_stop(&pb->planb_base->ch1);
502 if(cmd_dep != pb->ch1_cmd_phys) {
503 out_le32(&pb->planb_base->ch1.cmdptr,
504 virt_to_bus(pb->overlay_last1));
505 planb_dbdma_restart(&pb->planb_base->ch1);
508 pb->last_fr = pb->prev_last_fr;
509 pb->prev_last_fr = -999;
511 return;
514 static void suspend_overlay(struct planb *pb)
516 int fr = -1;
517 struct dbdma_cmd last;
519 DEBUG("PlanB: suspend_overlay: %d\n", pb->suspend);
521 if(pb->suspend++)
522 return;
523 if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) {
524 if(pb->last_fr == -2) {
525 fr = pb->prev_last_fr;
526 memcpy(&last, (void*)pb->last_cmd[fr], sizeof(last));
527 tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0);
529 if(overlay_is_active(pb)) {
530 planb_dbdma_stop(&pb->planb_base->ch2);
531 planb_dbdma_stop(&pb->planb_base->ch1);
532 pb->suspended.overlay = 1;
533 pb->suspended.frame = fr;
534 memcpy(&pb->suspended.cmd, &last, sizeof(last));
535 return;
538 pb->suspended.overlay = 0;
539 pb->suspended.frame = fr;
540 memcpy(&pb->suspended.cmd, &last, sizeof(last));
541 return;
544 static void resume_overlay(struct planb *pb)
547 DEBUG("PlanB: resume_overlay: %d\n", pb->suspend);
549 if(pb->suspend > 1)
550 return;
551 if(pb->suspended.frame != -1) {
552 memcpy((void*)pb->last_cmd[pb->suspended.frame],
553 &pb->suspended.cmd, sizeof(pb->suspended.cmd));
555 if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) {
556 goto finish;
558 if(pb->suspended.overlay) {
560 DEBUG("PlanB: overlay being resumed\n");
562 st_le16 (&pb->ch1_cmd->command, DBDMA_NOP);
563 st_le16 (&pb->ch2_cmd->command, DBDMA_NOP);
564 /* Set command buffer addresses */
565 st_le32(&pb->planb_base->ch1.cmdptr,
566 virt_to_bus(pb->overlay_last1));
567 out_le32(&pb->planb_base->ch2.cmdptr,
568 virt_to_bus(pb->overlay_last2));
569 /* Start the DMA controller */
570 out_le32 (&pb->planb_base->ch2.control,
571 PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE));
572 out_le32 (&pb->planb_base->ch1.control,
573 PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE));
574 } else if(pb->suspended.frame != -1) {
575 out_le32(&pb->planb_base->ch1.cmdptr,
576 virt_to_bus(pb->last_cmd[pb->suspended.frame]));
577 out_le32 (&pb->planb_base->ch1.control,
578 PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE));
581 finish:
582 pb->suspend--;
583 wake_up_interruptible(&pb->suspendq);
586 static void add_clip(struct planb *pb, struct video_clip *clip)
588 volatile unsigned char *base;
589 int xc = clip->x, yc = clip->y;
590 int wc = clip->width, hc = clip->height;
591 int ww = pb->win.width, hw = pb->win.height;
592 int x, y, xtmp1, xtmp2;
594 DEBUG("PlanB: clip %dx%d+%d+%d\n", wc, hc, xc, yc);
596 if(xc < 0) {
597 wc += xc;
598 xc = 0;
600 if(yc < 0) {
601 hc += yc;
602 yc = 0;
604 if(xc + wc > ww)
605 wc = ww - xc;
606 if(wc <= 0) /* Nothing to do */
607 return;
608 if(yc + hc > hw)
609 hc = hw - yc;
611 for (y = yc; y < yc+hc; y++) {
612 xtmp1=xc>>3;
613 xtmp2=(xc+wc)>>3;
614 base = pb->mask + y*96;
615 if(xc != 0 || wc >= 8)
616 *(base + xtmp1) &= (unsigned char)(0x00ff &
617 (0xff00 >> (xc&7)));
618 for (x = xtmp1 + 1; x < xtmp2; x++) {
619 *(base + x) = 0;
621 if(xc < (ww & ~0x7))
622 *(base + xtmp2) &= (unsigned char)(0x00ff >>
623 ((xc+wc) & 7));
626 return;
629 static void fill_cmd_buff(struct planb *pb)
631 int restore = 0;
632 volatile struct dbdma_cmd last;
634 DEBUG("PlanB: fill_cmd_buff()\n");
636 if(pb->overlay_last1 != pb->ch1_cmd) {
637 restore = 1;
638 last = *(pb->overlay_last1);
640 memset ((void *) pb->ch1_cmd, 0, 2 * pb->tab_size
641 * sizeof(struct dbdma_cmd));
642 cmd_buff (pb);
643 if(restore)
644 *(pb->overlay_last1) = last;
645 if(pb->suspended.overlay) {
646 unsigned long jump_addr = in_le32(&pb->overlay_last1->cmd_dep);
647 if(jump_addr != pb->ch1_cmd_phys) {
648 int i;
650 DEBUG("PlanB: adjusting ch1's jump address\n");
652 for(i = 0; i < MAX_GBUFFERS; i++) {
653 if(pb->need_pre_capture[i]) {
654 if(jump_addr == virt_to_bus(pb->pre_cmd[i]))
655 goto found;
656 } else {
657 if(jump_addr == virt_to_bus(pb->cap_cmd[i]))
658 goto found;
662 DEBUG("PlanB: not found...\n");
664 goto out;
665 found:
666 if(pb->need_pre_capture[i])
667 out_le32(&pb->pre_cmd[i]->phy_addr,
668 virt_to_bus(pb->overlay_last1));
669 else
670 out_le32(&pb->cap_cmd[i]->phy_addr,
671 virt_to_bus(pb->overlay_last1));
674 out:
675 pb->cmd_buff_inited = 1;
677 return;
680 static void cmd_buff(struct planb *pb)
682 int i, bpp, count, nlines, stepsize, interlace;
683 unsigned long base, jump, addr_com, addr_dep;
684 volatile struct dbdma_cmd *c1 = pb->ch1_cmd;
685 volatile struct dbdma_cmd *c2 = pb->ch2_cmd;
687 interlace = pb->win.interlace;
688 bpp = pb->win.bpp;
689 count = (bpp * ((pb->win.x + pb->win.width > pb->win.swidth) ?
690 (pb->win.swidth - pb->win.x) : pb->win.width));
691 nlines = ((pb->win.y + pb->win.height > pb->win.sheight) ?
692 (pb->win.sheight - pb->win.y) : pb->win.height);
694 /* Do video in: */
696 /* Preamble commands: */
697 addr_com = virt_to_bus(c1);
698 addr_dep = virt_to_bus(&c1->cmd_dep);
699 tab_cmd_dbdma(c1++, DBDMA_NOP, 0);
700 jump = virt_to_bus(c1+16); /* 14 by cmd_geo_setup() and 2 for padding */
701 if((c1 = cmd_geo_setup(c1, pb->win.width, pb->win.height, interlace,
702 bpp, 1, pb)) == NULL) {
703 printk(KERN_WARNING "PlanB: encountered serious problems\n");
704 tab_cmd_dbdma(pb->ch1_cmd + 1, DBDMA_STOP, 0);
705 tab_cmd_dbdma(pb->ch2_cmd + 1, DBDMA_STOP, 0);
706 return;
708 tab_cmd_store(c1++, addr_com, (unsigned)(DBDMA_NOP | BR_ALWAYS) << 16);
709 tab_cmd_store(c1++, addr_dep, jump);
710 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel),
711 PLANB_SET(FIELD_SYNC));
712 /* (1) wait for field sync to be set */
713 tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
714 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
715 PLANB_SET(ODD_FIELD));
716 /* wait for field sync to be cleared */
717 tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
718 /* if not odd field, wait until field sync is set again */
719 tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++;
720 /* assert ch_sync to ch2 */
721 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch2.control),
722 PLANB_SET(CH_SYNC));
723 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
724 PLANB_SET(DMA_ABORT));
726 base = (pb->frame_buffer_phys + pb->offset + pb->win.y * (pb->win.bpl
727 + pb->win.pad) + pb->win.x * bpp);
729 if (interlace) {
730 stepsize = 2;
731 jump = virt_to_bus(c1 + (nlines + 1) / 2);
732 } else {
733 stepsize = 1;
734 jump = virt_to_bus(c1 + nlines);
737 /* even field data: */
738 for (i=0; i < nlines; i += stepsize, c1++)
739 tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET,
740 count, base + i * (pb->win.bpl + pb->win.pad), jump);
742 /* For non-interlaced, we use even fields only */
743 if (!interlace)
744 goto cmd_tab_data_end;
746 /* Resync to odd field */
747 /* (2) wait for field sync to be set */
748 tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
749 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
750 PLANB_SET(ODD_FIELD));
751 /* wait for field sync to be cleared */
752 tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
753 /* if not odd field, wait until field sync is set again */
754 tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++;
755 /* assert ch_sync to ch2 */
756 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch2.control),
757 PLANB_SET(CH_SYNC));
758 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
759 PLANB_SET(DMA_ABORT));
761 /* odd field data: */
762 jump = virt_to_bus(c1 + nlines / 2);
763 for (i=1; i < nlines; i += stepsize, c1++)
764 tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count,
765 base + i * (pb->win.bpl + pb->win.pad), jump);
767 /* And jump back to the start */
768 cmd_tab_data_end:
769 pb->overlay_last1 = c1; /* keep a pointer to the last command */
770 tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->ch1_cmd));
772 /* Clipmask command buffer */
774 /* Preamble commands: */
775 tab_cmd_dbdma(c2++, DBDMA_NOP, 0);
776 tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.wait_sel),
777 PLANB_SET(CH_SYNC));
778 /* wait until ch1 asserts ch_sync */
779 tab_cmd_dbdma(c2++, DBDMA_NOP | WAIT_IFCLR, 0);
780 /* clear ch_sync asserted by ch1 */
781 tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.control),
782 PLANB_CLR(CH_SYNC));
783 tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.wait_sel),
784 PLANB_SET(FIELD_SYNC));
785 tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel),
786 PLANB_SET(ODD_FIELD));
788 /* jump to end of even field if appropriate */
789 /* this points to (interlace)? pos. C: pos. B */
790 jump = (interlace) ? virt_to_bus(c2 + (nlines + 1) / 2 + 2):
791 virt_to_bus(c2 + nlines + 2);
792 /* if odd field, skip over to odd field clipmasking */
793 tab_cmd_dbdma(c2++, DBDMA_NOP | BR_IFSET, jump);
795 /* even field mask: */
796 tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel),
797 PLANB_SET(DMA_ABORT));
798 /* this points to pos. B */
799 jump = (interlace) ? virt_to_bus(c2 + nlines + 1):
800 virt_to_bus(c2 + nlines);
801 base = virt_to_bus(pb->mask);
802 for (i=0; i < nlines; i += stepsize, c2++)
803 tab_cmd_gen(c2, OUTPUT_MORE | KEY_STREAM0 | BR_IFSET, 96,
804 base + i * 96, jump);
806 /* For non-interlaced, we use only even fields */
807 if(!interlace)
808 goto cmd_tab_mask_end;
810 /* odd field mask: */
811 /* C */ tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel),
812 PLANB_SET(DMA_ABORT));
813 /* this points to pos. B */
814 jump = virt_to_bus(c2 + nlines / 2);
815 base = virt_to_bus(pb->mask);
816 for (i=1; i < nlines; i += 2, c2++) /* abort if set */
817 tab_cmd_gen(c2, OUTPUT_MORE | KEY_STREAM0 | BR_IFSET, 96,
818 base + i * 96, jump);
820 /* Inform channel 1 and jump back to start */
821 cmd_tab_mask_end:
822 /* ok, I just realized this is kind of flawed. */
823 /* this part is reached only after odd field clipmasking. */
824 /* wanna clean up? */
825 /* wait for field sync to be set */
826 /* corresponds to fsync (1) of ch1 */
827 /* B */ tab_cmd_dbdma(c2++, DBDMA_NOP | WAIT_IFCLR, 0);
828 /* restart ch1, meant to clear any dead bit or something */
829 tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch1.control),
830 PLANB_CLR(RUN));
831 tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch1.control),
832 PLANB_SET(RUN));
833 pb->overlay_last2 = c2; /* keep a pointer to the last command */
834 /* start over even field clipmasking */
835 tab_cmd_dbdma(c2, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->ch2_cmd));
837 eieio();
838 return;
841 /*********************************/
842 /* grabdisplay support functions */
843 /*********************************/
845 static int palette2fmt[] = {
847 PLANB_GRAY,
851 PLANB_COLOUR32,
852 PLANB_COLOUR15,
863 #define PLANB_PALETTE_MAX 15
865 static int vgrab(struct planb *pb, struct video_mmap *mp)
867 unsigned int fr = mp->frame;
868 unsigned int format;
870 if(pb->rawbuf==NULL) {
871 int err;
872 if((err=grabbuf_alloc(pb)))
873 return err;
876 IDEBUG("PlanB: grab %d: %dx%d(%u)\n", pb->grabbing,
877 mp->width, mp->height, fr);
879 if(pb->grabbing >= MAX_GBUFFERS)
880 return -ENOBUFS;
881 if(fr > (MAX_GBUFFERS - 1) || fr < 0)
882 return -EINVAL;
883 if(mp->height <= 0 || mp->width <= 0)
884 return -EINVAL;
885 if(mp->format < 0 || mp->format >= PLANB_PALETTE_MAX)
886 return -EINVAL;
887 if((format = palette2fmt[mp->format]) == 0)
888 return -EINVAL;
889 if (mp->height * mp->width * format > PLANB_MAX_FBUF) /* format = bpp */
890 return -EINVAL;
892 planb_lock(pb);
893 if(mp->width != pb->gwidth[fr] || mp->height != pb->gheight[fr] ||
894 format != pb->gfmt[fr] || (pb->gnorm_switch[fr])) {
895 int i;
896 #ifndef PLANB_GSCANLINE
897 unsigned int osize = pb->gwidth[fr] * pb->gheight[fr]
898 * pb->gfmt[fr];
899 unsigned int nsize = mp->width * mp->height * format;
900 #endif
902 IDEBUG("PlanB: gwidth = %d, gheight = %d, mp->format = %u\n",
903 mp->width, mp->height, mp->format);
905 #ifndef PLANB_GSCANLINE
906 if(pb->gnorm_switch[fr])
907 nsize = 0;
908 if (nsize < osize) {
909 for(i = pb->gbuf_idx[fr]; osize > 0; i++) {
910 memset((void *)pb->rawbuf[i], 0, PAGE_SIZE);
911 osize -= PAGE_SIZE;
914 for(i = pb->l_fr_addr_idx[fr]; i < pb->l_fr_addr_idx[fr]
915 + pb->lnum[fr]; i++)
916 memset((void *)pb->rawbuf[i], 0, PAGE_SIZE);
917 #else
918 /* XXX TODO */
920 if(pb->gnorm_switch[fr])
921 memset((void *)pb->gbuffer[fr], 0,
922 pb->gbytes_per_line * pb->gheight[fr]);
923 else {
924 if(mp->
925 for(i = 0; i < pb->gheight[fr]; i++) {
926 memset((void *)(pb->gbuffer[fr]
927 + pb->gbytes_per_line * i
931 #endif
932 pb->gwidth[fr] = mp->width;
933 pb->gheight[fr] = mp->height;
934 pb->gfmt[fr] = format;
935 pb->last_cmd[fr] = setup_grab_cmd(fr, pb);
936 planb_pre_capture(fr, pb->gfmt[fr], pb); /* gfmt = bpp */
937 pb->need_pre_capture[fr] = 1;
938 pb->gnorm_switch[fr] = 0;
939 } else
940 pb->need_pre_capture[fr] = 0;
941 pb->frame_stat[fr] = GBUFFER_GRABBING;
942 if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) {
944 IDEBUG("PlanB: ch1 inactive, initiating grabbing\n");
946 planb_dbdma_stop(&pb->planb_base->ch1);
947 if(pb->need_pre_capture[fr]) {
949 IDEBUG("PlanB: padding pre-capture sequence\n");
951 out_le32 (&pb->planb_base->ch1.cmdptr,
952 virt_to_bus(pb->pre_cmd[fr]));
953 } else {
954 tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0);
955 tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0);
956 /* let's be on the safe side. here is not timing critical. */
957 tab_cmd_dbdma((pb->cap_cmd[fr] + 1), DBDMA_NOP, 0);
958 out_le32 (&pb->planb_base->ch1.cmdptr,
959 virt_to_bus(pb->cap_cmd[fr]));
961 planb_dbdma_restart(&pb->planb_base->ch1);
962 pb->last_fr = fr;
963 } else {
964 int i;
966 IDEBUG("PlanB: ch1 active, grabbing being queued\n");
968 if((pb->last_fr == -1) || ((pb->last_fr == -2) &&
969 overlay_is_active(pb))) {
971 IDEBUG("PlanB: overlay is active, grabbing defered\n");
973 tab_cmd_dbdma(pb->last_cmd[fr],
974 DBDMA_NOP | BR_ALWAYS,
975 virt_to_bus(pb->ch1_cmd));
976 if(pb->need_pre_capture[fr]) {
978 IDEBUG("PlanB: padding pre-capture sequence\n");
980 tab_cmd_store(pb->pre_cmd[fr],
981 virt_to_bus(&pb->overlay_last1->cmd_dep),
982 virt_to_bus(pb->ch1_cmd));
983 eieio();
984 out_le32 (&pb->overlay_last1->cmd_dep,
985 virt_to_bus(pb->pre_cmd[fr]));
986 } else {
987 tab_cmd_store(pb->cap_cmd[fr],
988 virt_to_bus(&pb->overlay_last1->cmd_dep),
989 virt_to_bus(pb->ch1_cmd));
990 tab_cmd_dbdma((pb->cap_cmd[fr] + 1),
991 DBDMA_NOP, 0);
992 eieio();
993 out_le32 (&pb->overlay_last1->cmd_dep,
994 virt_to_bus(pb->cap_cmd[fr]));
996 for(i = 0; overlay_is_active(pb) && i < 999; i++)
997 IDEBUG("PlanB: waiting for overlay done\n");
998 tab_cmd_dbdma(pb->ch1_cmd, DBDMA_NOP, 0);
999 pb->prev_last_fr = fr;
1000 pb->last_fr = -2;
1001 } else if(pb->last_fr == -2) {
1003 IDEBUG("PlanB: mixed mode detected, grabbing"
1004 " will be done before activating overlay\n");
1006 tab_cmd_dbdma(pb->ch1_cmd, DBDMA_NOP, 0);
1007 if(pb->need_pre_capture[fr]) {
1009 IDEBUG("PlanB: padding pre-capture sequence\n");
1011 tab_cmd_dbdma(pb->last_cmd[pb->prev_last_fr],
1012 DBDMA_NOP | BR_ALWAYS,
1013 virt_to_bus(pb->pre_cmd[fr]));
1014 eieio();
1015 } else {
1016 tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0);
1017 if(pb->gwidth[pb->prev_last_fr] !=
1018 pb->gwidth[fr]
1019 || pb->gheight[pb->prev_last_fr] !=
1020 pb->gheight[fr]
1021 || pb->gfmt[pb->prev_last_fr] !=
1022 pb->gfmt[fr])
1023 tab_cmd_dbdma((pb->cap_cmd[fr] + 1),
1024 DBDMA_NOP, 0);
1025 else
1026 tab_cmd_dbdma((pb->cap_cmd[fr] + 1),
1027 DBDMA_NOP | BR_ALWAYS,
1028 virt_to_bus(pb->cap_cmd[fr] + 16));
1029 tab_cmd_dbdma(pb->last_cmd[pb->prev_last_fr],
1030 DBDMA_NOP | BR_ALWAYS,
1031 virt_to_bus(pb->cap_cmd[fr]));
1032 eieio();
1034 tab_cmd_dbdma(pb->last_cmd[fr],
1035 DBDMA_NOP | BR_ALWAYS,
1036 virt_to_bus(pb->ch1_cmd));
1037 eieio();
1038 pb->prev_last_fr = fr;
1039 pb->last_fr = -2;
1040 } else {
1042 IDEBUG("PlanB: active grabbing session detected\n");
1044 if(pb->need_pre_capture[fr]) {
1046 IDEBUG("PlanB: padding pre-capture sequence\n");
1048 tab_cmd_dbdma(pb->last_cmd[pb->last_fr],
1049 DBDMA_NOP | BR_ALWAYS,
1050 virt_to_bus(pb->pre_cmd[fr]));
1051 eieio();
1052 } else {
1053 tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0);
1054 tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0);
1055 if(pb->gwidth[pb->last_fr] != pb->gwidth[fr]
1056 || pb->gheight[pb->last_fr] !=
1057 pb->gheight[fr]
1058 || pb->gfmt[pb->last_fr] !=
1059 pb->gfmt[fr])
1060 tab_cmd_dbdma((pb->cap_cmd[fr] + 1),
1061 DBDMA_NOP, 0);
1062 else
1063 tab_cmd_dbdma((pb->cap_cmd[fr] + 1),
1064 DBDMA_NOP | BR_ALWAYS,
1065 virt_to_bus(pb->cap_cmd[fr] + 16));
1066 tab_cmd_dbdma(pb->last_cmd[pb->last_fr],
1067 DBDMA_NOP | BR_ALWAYS,
1068 virt_to_bus(pb->cap_cmd[fr]));
1069 eieio();
1071 pb->last_fr = fr;
1073 if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) {
1075 IDEBUG("PlanB: became inactive in the mean time..."
1076 "reactivating\n");
1078 planb_dbdma_stop(&pb->planb_base->ch1);
1079 out_le32 (&pb->planb_base->ch1.cmdptr,
1080 virt_to_bus(pb->cap_cmd[fr]));
1081 planb_dbdma_restart(&pb->planb_base->ch1);
1084 pb->grabbing++;
1085 planb_unlock(pb);
1087 return 0;
1090 static void planb_pre_capture(int fr, int bpp, struct planb *pb)
1092 volatile struct dbdma_cmd *c1 = pb->pre_cmd[fr];
1093 int interlace = (pb->gheight[fr] > pb->maxlines/2)? 1: 0;
1095 tab_cmd_dbdma(c1++, DBDMA_NOP, 0);
1096 if((c1 = cmd_geo_setup(c1, pb->gwidth[fr], pb->gheight[fr], interlace,
1097 bpp, 0, pb)) == NULL) {
1098 printk(KERN_WARNING "PlanB: encountered some problems\n");
1099 tab_cmd_dbdma(pb->pre_cmd[fr] + 1, DBDMA_STOP, 0);
1100 return;
1102 /* Sync to even field */
1103 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel),
1104 PLANB_SET(FIELD_SYNC));
1105 tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
1106 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
1107 PLANB_SET(ODD_FIELD));
1108 tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
1109 tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++;
1110 tab_cmd_dbdma(c1++, DBDMA_NOP | INTR_ALWAYS, 0);
1111 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
1112 PLANB_SET(DMA_ABORT));
1113 /* For non-interlaced, we use even fields only */
1114 if (pb->gheight[fr] <= pb->maxlines/2)
1115 goto cmd_tab_data_end;
1116 /* Sync to odd field */
1117 tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
1118 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
1119 PLANB_SET(ODD_FIELD));
1120 tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
1121 tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++;
1122 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
1123 PLANB_SET(DMA_ABORT));
1124 cmd_tab_data_end:
1125 tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->cap_cmd[fr]));
1127 eieio();
1130 static volatile struct dbdma_cmd *setup_grab_cmd(int fr, struct planb *pb)
1132 int i, bpp, count, nlines, stepsize, interlace;
1133 #ifdef PLANB_GSCANLINE
1134 int scanline;
1135 #else
1136 int nlpp, leftover1;
1137 unsigned long base;
1138 #endif
1139 unsigned long jump;
1140 int pagei;
1141 volatile struct dbdma_cmd *c1;
1142 volatile struct dbdma_cmd *jump_addr;
1144 c1 = pb->cap_cmd[fr];
1145 interlace = (pb->gheight[fr] > pb->maxlines/2)? 1: 0;
1146 bpp = pb->gfmt[fr]; /* gfmt = bpp */
1147 count = bpp * pb->gwidth[fr];
1148 nlines = pb->gheight[fr];
1149 #ifdef PLANB_GSCANLINE
1150 scanline = pb->gbytes_per_line;
1151 #else
1152 pb->lsize[fr] = count;
1153 pb->lnum[fr] = 0;
1154 #endif
1156 /* Do video in: */
1158 /* Preamble commands: */
1159 tab_cmd_dbdma(c1++, DBDMA_NOP, 0);
1160 tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(c1 + 16)); c1++;
1161 if((c1 = cmd_geo_setup(c1, pb->gwidth[fr], pb->gheight[fr], interlace,
1162 bpp, 0, pb)) == NULL) {
1163 printk(KERN_WARNING "PlanB: encountered serious problems\n");
1164 tab_cmd_dbdma(pb->cap_cmd[fr] + 1, DBDMA_STOP, 0);
1165 return (pb->cap_cmd[fr] + 2);
1167 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel),
1168 PLANB_SET(FIELD_SYNC));
1169 tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
1170 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
1171 PLANB_SET(ODD_FIELD));
1172 tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
1173 tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++;
1174 tab_cmd_dbdma(c1++, DBDMA_NOP | INTR_ALWAYS, 0);
1175 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
1176 PLANB_SET(DMA_ABORT));
1178 if (interlace) {
1179 stepsize = 2;
1180 jump_addr = c1 + TAB_FACTOR * (nlines + 1) / 2;
1181 } else {
1182 stepsize = 1;
1183 jump_addr = c1 + TAB_FACTOR * nlines;
1185 jump = virt_to_bus(jump_addr);
1187 /* even field data: */
1189 pagei = pb->gbuf_idx[fr];
1190 #ifdef PLANB_GSCANLINE
1191 for (i = 0; i < nlines; i += stepsize) {
1192 tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count,
1193 virt_to_bus(pb->rawbuf[pagei
1194 + i * scanline / PAGE_SIZE]), jump);
1196 #else
1197 i = 0;
1198 leftover1 = 0;
1199 do {
1200 int j;
1202 base = virt_to_bus(pb->rawbuf[pagei]);
1203 nlpp = (PAGE_SIZE - leftover1) / count / stepsize;
1204 for(j = 0; j < nlpp && i < nlines; j++, i += stepsize, c1++)
1205 tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET,
1206 count, base + count * j * stepsize + leftover1, jump);
1207 if(i < nlines) {
1208 int lov0 = PAGE_SIZE - count * nlpp * stepsize - leftover1;
1210 if(lov0 == 0)
1211 leftover1 = 0;
1212 else {
1213 if(lov0 >= count) {
1214 tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, base
1215 + count * nlpp * stepsize + leftover1, jump);
1216 } else {
1217 pb->l_to_addr[fr][pb->lnum[fr]] = pb->rawbuf[pagei]
1218 + count * nlpp * stepsize + leftover1;
1219 pb->l_to_next_idx[fr][pb->lnum[fr]] = pagei + 1;
1220 pb->l_to_next_size[fr][pb->lnum[fr]] = count - lov0;
1221 tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count,
1222 virt_to_bus(pb->rawbuf[pb->l_fr_addr_idx[fr]
1223 + pb->lnum[fr]]), jump);
1224 if(++pb->lnum[fr] > MAX_LNUM)
1225 pb->lnum[fr]--;
1227 leftover1 = count * stepsize - lov0;
1228 i += stepsize;
1231 pagei++;
1232 } while(i < nlines);
1233 tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, jump);
1234 c1 = jump_addr;
1235 #endif /* PLANB_GSCANLINE */
1237 /* For non-interlaced, we use even fields only */
1238 if (!interlace)
1239 goto cmd_tab_data_end;
1241 /* Sync to odd field */
1242 tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
1243 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
1244 PLANB_SET(ODD_FIELD));
1245 tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
1246 tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++;
1247 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
1248 PLANB_SET(DMA_ABORT));
1250 /* odd field data: */
1251 jump_addr = c1 + TAB_FACTOR * nlines / 2;
1252 jump = virt_to_bus(jump_addr);
1253 #ifdef PLANB_GSCANLINE
1254 for (i = 1; i < nlines; i += stepsize) {
1255 tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count,
1256 virt_to_bus(pb->rawbuf[pagei
1257 + i * scanline / PAGE_SIZE]), jump);
1259 #else
1260 i = 1;
1261 leftover1 = 0;
1262 pagei = pb->gbuf_idx[fr];
1263 if(nlines <= 1)
1264 goto skip;
1265 do {
1266 int j;
1268 base = virt_to_bus(pb->rawbuf[pagei]);
1269 nlpp = (PAGE_SIZE - leftover1) / count / stepsize;
1270 if(leftover1 >= count) {
1271 tab_cmd_gen(c1++, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count,
1272 base + leftover1 - count, jump);
1273 i += stepsize;
1275 for(j = 0; j < nlpp && i < nlines; j++, i += stepsize, c1++)
1276 tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count,
1277 base + count * (j * stepsize + 1) + leftover1, jump);
1278 if(i < nlines) {
1279 int lov0 = PAGE_SIZE - count * nlpp * stepsize - leftover1;
1281 if(lov0 == 0)
1282 leftover1 = 0;
1283 else {
1284 if(lov0 > count) {
1285 pb->l_to_addr[fr][pb->lnum[fr]] = pb->rawbuf[pagei]
1286 + count * (nlpp * stepsize + 1) + leftover1;
1287 pb->l_to_next_idx[fr][pb->lnum[fr]] = pagei + 1;
1288 pb->l_to_next_size[fr][pb->lnum[fr]] = count * stepsize
1289 - lov0;
1290 tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count,
1291 virt_to_bus(pb->rawbuf[pb->l_fr_addr_idx[fr]
1292 + pb->lnum[fr]]), jump);
1293 if(++pb->lnum[fr] > MAX_LNUM)
1294 pb->lnum[fr]--;
1295 i += stepsize;
1297 leftover1 = count * stepsize - lov0;
1300 pagei++;
1301 } while(i < nlines);
1302 skip:
1303 tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, jump);
1304 c1 = jump_addr;
1305 #endif /* PLANB_GSCANLINE */
1307 cmd_tab_data_end:
1308 tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->intr_stat),
1309 (fr << 9) | PLANB_FRM_IRQ | PLANB_GEN_IRQ);
1310 /* stop it */
1311 tab_cmd_dbdma(c1, DBDMA_STOP, 0);
1313 eieio();
1314 return c1;
1317 static irqreturn_t planb_irq(int irq, void *dev_id)
1319 unsigned int stat, astat;
1320 struct planb *pb = (struct planb *)dev_id;
1322 IDEBUG("PlanB: planb_irq()\n");
1324 /* get/clear interrupt status bits */
1325 eieio();
1326 stat = in_le32(&pb->planb_base->intr_stat);
1327 astat = stat & pb->intr_mask;
1328 out_le32(&pb->planb_base->intr_stat, PLANB_FRM_IRQ
1329 & ~astat & stat & ~PLANB_GEN_IRQ);
1330 IDEBUG("PlanB: stat = %X, astat = %X\n", stat, astat);
1332 if(astat & PLANB_FRM_IRQ) {
1333 unsigned int fr = stat >> 9;
1334 #ifndef PLANB_GSCANLINE
1335 int i;
1336 #endif
1337 IDEBUG("PlanB: PLANB_FRM_IRQ\n");
1339 pb->gcount++;
1341 IDEBUG("PlanB: grab %d: fr = %d, gcount = %d\n",
1342 pb->grabbing, fr, pb->gcount);
1343 #ifndef PLANB_GSCANLINE
1344 IDEBUG("PlanB: %d * %d bytes are being copied over\n",
1345 pb->lnum[fr], pb->lsize[fr]);
1346 for(i = 0; i < pb->lnum[fr]; i++) {
1347 int first = pb->lsize[fr] - pb->l_to_next_size[fr][i];
1349 memcpy(pb->l_to_addr[fr][i],
1350 pb->rawbuf[pb->l_fr_addr_idx[fr] + i],
1351 first);
1352 memcpy(pb->rawbuf[pb->l_to_next_idx[fr][i]],
1353 pb->rawbuf[pb->l_fr_addr_idx[fr] + i] + first,
1354 pb->l_to_next_size[fr][i]);
1356 #endif
1357 pb->frame_stat[fr] = GBUFFER_DONE;
1358 pb->grabbing--;
1359 wake_up_interruptible(&pb->capq);
1360 return IRQ_HANDLED;
1362 /* incorrect interrupts? */
1363 pb->intr_mask = PLANB_CLR_IRQ;
1364 out_le32(&pb->planb_base->intr_stat, PLANB_CLR_IRQ);
1365 printk(KERN_ERR "PlanB: IRQ lockup, cleared intrrupts"
1366 " unconditionally\n");
1367 return IRQ_HANDLED;
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 wait_event(pb->capq, !pb->grabbing);
1614 pb->maxlines = maxlines;
1615 pb->win.norm = v.norm;
1616 /* Stop overlay if running */
1617 suspend_overlay(pb);
1618 for(i = 0; i < MAX_GBUFFERS; i++)
1619 pb->gnorm_switch[i] = 1;
1620 /* I know it's an overkill, but.... */
1621 fill_cmd_buff(pb);
1622 /* ok, now init it accordingly */
1623 saa_init_regs (pb);
1624 /* restart overlay if it was running */
1625 resume_overlay(pb);
1626 planb_unlock(pb);
1629 switch(v.channel)
1631 case 0: /* Composite */
1632 saa_set (SAA7196_IOCC,
1633 ((saa_regs[pb->win.norm][SAA7196_IOCC] &
1634 ~7) | 3), pb);
1635 break;
1636 case 1: /* SVHS */
1637 saa_set (SAA7196_IOCC,
1638 ((saa_regs[pb->win.norm][SAA7196_IOCC] &
1639 ~7) | 4), pb);
1640 break;
1641 default:
1642 return -EINVAL;
1643 break;
1646 return 0;
1648 case VIDIOCGPICT:
1650 struct video_picture vp = pb->picture;
1652 DEBUG("PlanB: IOCTL VIDIOCGPICT\n");
1654 switch(pb->win.color_fmt) {
1655 case PLANB_GRAY:
1656 vp.palette = VIDEO_PALETTE_GREY;
1657 case PLANB_COLOUR15:
1658 vp.palette = VIDEO_PALETTE_RGB555;
1659 break;
1660 case PLANB_COLOUR32:
1661 vp.palette = VIDEO_PALETTE_RGB32;
1662 break;
1663 default:
1664 vp.palette = 0;
1665 break;
1668 if(copy_to_user(arg,&vp,sizeof(vp)))
1669 return -EFAULT;
1670 return 0;
1672 case VIDIOCSPICT:
1674 struct video_picture vp;
1676 DEBUG("PlanB: IOCTL VIDIOCSPICT\n");
1678 if(copy_from_user(&vp,arg,sizeof(vp)))
1679 return -EFAULT;
1680 pb->picture = vp;
1681 /* Should we do sanity checks here? */
1682 saa_set (SAA7196_BRIG, (unsigned char)
1683 ((pb->picture.brightness) >> 8), pb);
1684 saa_set (SAA7196_HUEC, (unsigned char)
1685 ((pb->picture.hue) >> 8) ^ 0x80, pb);
1686 saa_set (SAA7196_CSAT, (unsigned char)
1687 ((pb->picture.colour) >> 9), pb);
1688 saa_set (SAA7196_CONT, (unsigned char)
1689 ((pb->picture.contrast) >> 9), pb);
1691 return 0;
1693 case VIDIOCSWIN:
1695 struct video_window vw;
1696 struct video_clip clip;
1697 int i;
1699 DEBUG("PlanB: IOCTL VIDIOCSWIN\n");
1701 if(copy_from_user(&vw,arg,sizeof(vw)))
1702 return -EFAULT;
1704 planb_lock(pb);
1705 /* Stop overlay if running */
1706 suspend_overlay(pb);
1707 pb->win.interlace = (vw.height > pb->maxlines/2)? 1: 0;
1708 if (pb->win.x != vw.x ||
1709 pb->win.y != vw.y ||
1710 pb->win.width != vw.width ||
1711 pb->win.height != vw.height ||
1712 !pb->cmd_buff_inited) {
1713 pb->win.x = vw.x;
1714 pb->win.y = vw.y;
1715 pb->win.width = vw.width;
1716 pb->win.height = vw.height;
1717 fill_cmd_buff(pb);
1719 /* Reset clip mask */
1720 memset ((void *) pb->mask, 0xff, (pb->maxlines
1721 * ((PLANB_MAXPIXELS + 7) & ~7)) / 8);
1722 /* Add any clip rects */
1723 for (i = 0; i < vw.clipcount; i++) {
1724 if (copy_from_user(&clip, vw.clips + i,
1725 sizeof(struct video_clip)))
1726 return -EFAULT;
1727 add_clip(pb, &clip);
1729 /* restart overlay if it was running */
1730 resume_overlay(pb);
1731 planb_unlock(pb);
1732 return 0;
1734 case VIDIOCGWIN:
1736 struct video_window vw;
1738 DEBUG("PlanB: IOCTL VIDIOCGWIN\n");
1740 vw.x=pb->win.x;
1741 vw.y=pb->win.y;
1742 vw.width=pb->win.width;
1743 vw.height=pb->win.height;
1744 vw.chromakey=0;
1745 vw.flags=0;
1746 if(pb->win.interlace)
1747 vw.flags|=VIDEO_WINDOW_INTERLACE;
1748 if(copy_to_user(arg,&vw,sizeof(vw)))
1749 return -EFAULT;
1750 return 0;
1752 case VIDIOCSYNC: {
1753 int i;
1755 IDEBUG("PlanB: IOCTL VIDIOCSYNC\n");
1757 if(copy_from_user((void *)&i,arg,sizeof(int)))
1758 return -EFAULT;
1760 IDEBUG("PlanB: sync to frame %d\n", i);
1762 if(i > (MAX_GBUFFERS - 1) || i < 0)
1763 return -EINVAL;
1764 chk_grab:
1765 switch (pb->frame_stat[i]) {
1766 case GBUFFER_UNUSED:
1767 return -EINVAL;
1768 case GBUFFER_GRABBING:
1769 IDEBUG("PlanB: waiting for grab"
1770 " done (%d)\n", i);
1771 interruptible_sleep_on(&pb->capq);
1772 if(signal_pending(current))
1773 return -EINTR;
1774 goto chk_grab;
1775 case GBUFFER_DONE:
1776 pb->frame_stat[i] = GBUFFER_UNUSED;
1777 break;
1779 return 0;
1782 case VIDIOCMCAPTURE:
1784 struct video_mmap vm;
1785 volatile unsigned int status;
1787 IDEBUG("PlanB: IOCTL VIDIOCMCAPTURE\n");
1789 if(copy_from_user((void *) &vm,(void *)arg,sizeof(vm)))
1790 return -EFAULT;
1791 status = pb->frame_stat[vm.frame];
1792 if (status != GBUFFER_UNUSED)
1793 return -EBUSY;
1795 return vgrab(pb, &vm);
1798 case VIDIOCGMBUF:
1800 int i;
1801 struct video_mbuf vm;
1803 DEBUG("PlanB: IOCTL VIDIOCGMBUF\n");
1805 memset(&vm, 0 , sizeof(vm));
1806 vm.size = PLANB_MAX_FBUF * MAX_GBUFFERS;
1807 vm.frames = MAX_GBUFFERS;
1808 for(i = 0; i<MAX_GBUFFERS; i++)
1809 vm.offsets[i] = PLANB_MAX_FBUF * i;
1810 if(copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
1811 return -EFAULT;
1812 return 0;
1815 case PLANBIOCGSAAREGS:
1817 struct planb_saa_regs preg;
1819 DEBUG("PlanB: IOCTL PLANBIOCGSAAREGS\n");
1821 if(copy_from_user(&preg, arg, sizeof(preg)))
1822 return -EFAULT;
1823 if(preg.addr >= SAA7196_NUMREGS)
1824 return -EINVAL;
1825 preg.val = saa_regs[pb->win.norm][preg.addr];
1826 if(copy_to_user((void *)arg, (void *)&preg,
1827 sizeof(preg)))
1828 return -EFAULT;
1829 return 0;
1832 case PLANBIOCSSAAREGS:
1834 struct planb_saa_regs preg;
1836 DEBUG("PlanB: IOCTL PLANBIOCSSAAREGS\n");
1838 if(copy_from_user(&preg, arg, sizeof(preg)))
1839 return -EFAULT;
1840 if(preg.addr >= SAA7196_NUMREGS)
1841 return -EINVAL;
1842 saa_set (preg.addr, preg.val, pb);
1843 return 0;
1846 case PLANBIOCGSTAT:
1848 struct planb_stat_regs pstat;
1850 DEBUG("PlanB: IOCTL PLANBIOCGSTAT\n");
1852 pstat.ch1_stat = in_le32(&pb->planb_base->ch1.status);
1853 pstat.ch2_stat = in_le32(&pb->planb_base->ch2.status);
1854 pstat.saa_stat0 = saa_status(0, pb);
1855 pstat.saa_stat1 = saa_status(1, pb);
1857 if(copy_to_user((void *)arg, (void *)&pstat,
1858 sizeof(pstat)))
1859 return -EFAULT;
1860 return 0;
1863 case PLANBIOCSMODE: {
1864 int v;
1866 DEBUG("PlanB: IOCTL PLANBIOCSMODE\n");
1868 if(copy_from_user(&v, arg, sizeof(v)))
1869 return -EFAULT;
1871 switch(v)
1873 case PLANB_TV_MODE:
1874 saa_set (SAA7196_STDC,
1875 (saa_regs[pb->win.norm][SAA7196_STDC] &
1876 0x7f), pb);
1877 break;
1878 case PLANB_VTR_MODE:
1879 saa_set (SAA7196_STDC,
1880 (saa_regs[pb->win.norm][SAA7196_STDC] |
1881 0x80), pb);
1882 break;
1883 default:
1884 return -EINVAL;
1885 break;
1887 pb->win.mode = v;
1888 return 0;
1890 case PLANBIOCGMODE: {
1891 int v=pb->win.mode;
1893 DEBUG("PlanB: IOCTL PLANBIOCGMODE\n");
1895 if(copy_to_user(arg,&v,sizeof(v)))
1896 return -EFAULT;
1897 return 0;
1899 #ifdef PLANB_GSCANLINE
1900 case PLANBG_GRAB_BPL: {
1901 int v=pb->gbytes_per_line;
1903 DEBUG("PlanB: IOCTL PLANBG_GRAB_BPL\n");
1905 if(copy_to_user(arg,&v,sizeof(v)))
1906 return -EFAULT;
1907 return 0;
1909 #endif /* PLANB_GSCANLINE */
1910 case PLANB_INTR_DEBUG: {
1911 int i;
1913 DEBUG("PlanB: IOCTL PLANB_INTR_DEBUG\n");
1915 if(copy_from_user(&i, arg, sizeof(i)))
1916 return -EFAULT;
1918 /* avoid hang ups all together */
1919 for (i = 0; i < MAX_GBUFFERS; i++) {
1920 if(pb->frame_stat[i] == GBUFFER_GRABBING) {
1921 pb->frame_stat[i] = GBUFFER_DONE;
1924 if(pb->grabbing)
1925 pb->grabbing--;
1926 wake_up_interruptible(&pb->capq);
1927 return 0;
1929 case PLANB_INV_REGS: {
1930 int i;
1931 struct planb_any_regs any;
1933 DEBUG("PlanB: IOCTL PLANB_INV_REGS\n");
1935 if(copy_from_user(&any, arg, sizeof(any)))
1936 return -EFAULT;
1937 if(any.offset < 0 || any.offset + any.bytes > 0x400)
1938 return -EINVAL;
1939 if(any.bytes > 128)
1940 return -EINVAL;
1941 for (i = 0; i < any.bytes; i++) {
1942 any.data[i] =
1943 in_8((unsigned char *)pb->planb_base
1944 + any.offset + i);
1946 if(copy_to_user(arg,&any,sizeof(any)))
1947 return -EFAULT;
1948 return 0;
1950 default:
1952 DEBUG("PlanB: Unimplemented IOCTL\n");
1953 return -ENOIOCTLCMD;
1955 /* Some IOCTLs are currently unsupported on PlanB */
1956 case VIDIOCGTUNER: {
1957 DEBUG("PlanB: IOCTL VIDIOCGTUNER\n");
1958 goto unimplemented; }
1959 case VIDIOCSTUNER: {
1960 DEBUG("PlanB: IOCTL VIDIOCSTUNER\n");
1961 goto unimplemented; }
1962 case VIDIOCSFREQ: {
1963 DEBUG("PlanB: IOCTL VIDIOCSFREQ\n");
1964 goto unimplemented; }
1965 case VIDIOCGFREQ: {
1966 DEBUG("PlanB: IOCTL VIDIOCGFREQ\n");
1967 goto unimplemented; }
1968 case VIDIOCKEY: {
1969 DEBUG("PlanB: IOCTL VIDIOCKEY\n");
1970 goto unimplemented; }
1971 case VIDIOCSAUDIO: {
1972 DEBUG("PlanB: IOCTL VIDIOCSAUDIO\n");
1973 goto unimplemented; }
1974 case VIDIOCGAUDIO: {
1975 DEBUG("PlanB: IOCTL VIDIOCGAUDIO\n");
1976 goto unimplemented; }
1977 unimplemented:
1978 DEBUG(" Unimplemented\n");
1979 return -ENOIOCTLCMD;
1981 return 0;
1984 static int planb_mmap(struct vm_area_struct *vma, struct video_device *dev, const char *adr, unsigned long size)
1986 int i;
1987 struct planb *pb = (struct planb *)dev;
1988 unsigned long start = (unsigned long)adr;
1990 if (size > MAX_GBUFFERS * PLANB_MAX_FBUF)
1991 return -EINVAL;
1992 if (!pb->rawbuf) {
1993 int err;
1994 if((err=grabbuf_alloc(pb)))
1995 return err;
1997 for (i = 0; i < pb->rawbuf_size; i++) {
1998 unsigned long pfn;
2000 pfn = virt_to_phys((void *)pb->rawbuf[i]) >> PAGE_SHIFT;
2001 if (remap_pfn_range(vma, start, pfn, PAGE_SIZE, PAGE_SHARED))
2002 return -EAGAIN;
2003 start += PAGE_SIZE;
2004 if (size <= PAGE_SIZE)
2005 break;
2006 size -= PAGE_SIZE;
2008 return 0;
2011 static struct video_device planb_template=
2013 .owner = THIS_MODULE,
2014 .name = PLANB_DEVICE_NAME,
2015 .type = VID_TYPE_OVERLAY,
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 mutex_init(&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", 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_is(powermac))
2159 return 0;
2161 planb_devices = of_find_node_by_name(NULL, "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 of_node_put(planb_devices);
2177 return 0;
2180 if (planb_devices->n_intrs == 0) {
2181 printk(KERN_WARNING "PlanB: no intrs for device %s\n",
2182 planb_devices->full_name);
2183 of_node_put(planb_devices);
2184 return 0;
2185 } else {
2186 irq = planb_devices->intrs[0].line;
2189 /* Initialize PlanB's PCI registers */
2191 /* There is a bug with the way OF assigns addresses
2192 to the devices behind the chaos bridge.
2193 control needs only 0x1000 of space, but decodes only
2194 the upper 16 bits. It therefore occupies a full 64K.
2195 OF assigns the planb controller memory within this space;
2196 so we need to change that here in order to access planb. */
2198 /* We remap to 0xf1000000 in hope that nobody uses it ! */
2200 bus = (planb_devices->addrs[0].space >> 16) & 0xff;
2201 dev_fn = (planb_devices->addrs[0].space >> 8) & 0xff;
2202 confreg = planb_devices->addrs[0].space & 0xff;
2203 old_base = planb_devices->addrs[0].address;
2204 new_base = 0xf1000000;
2205 of_node_put(planb_devices);
2207 DEBUG("PlanB: Found on bus %d, dev %d, func %d, "
2208 "membase 0x%x (base reg. 0x%x)\n",
2209 bus, PCI_SLOT(dev_fn), PCI_FUNC(dev_fn), old_base, confreg);
2211 pdev = pci_get_bus_and_slot(bus, dev_fn);
2212 if (!pdev) {
2213 printk(KERN_ERR "planb: cannot find slot\n");
2214 goto err_out;
2217 /* Enable response in memory space, bus mastering,
2218 use memory write and invalidate */
2219 rc = pci_enable_device(pdev);
2220 if (rc) {
2221 printk(KERN_ERR "planb: cannot enable PCI device %s\n",
2222 pci_name(pdev));
2223 goto err_out;
2225 rc = pci_set_mwi(pdev);
2226 if (rc) {
2227 printk(KERN_ERR "planb: cannot enable MWI on PCI device %s\n",
2228 pci_name(pdev));
2229 goto err_out_disable;
2231 pci_set_master(pdev);
2233 /* Set the new base address */
2234 pci_write_config_dword (pdev, confreg, new_base);
2236 planb_regs = (volatile struct planb_registers *)
2237 ioremap (new_base, 0x400);
2238 pb->planb_base = planb_regs;
2239 pb->planb_base_phys = (struct planb_registers *)new_base;
2240 pb->irq = irq;
2241 pb->dev = pdev;
2243 return planb_num;
2245 err_out_disable:
2246 pci_disable_device(pdev);
2247 err_out:
2248 /* FIXME handle error */ /* comment moved from pci_find_slot, above */
2249 pci_dev_put(pdev);
2250 return 0;
2253 static void release_planb(void)
2255 int i;
2256 struct planb *pb;
2258 for (i=0;i<planb_num; i++)
2260 pb=&planbs[i];
2262 /* stop and flash DMAs unconditionally */
2263 planb_dbdma_stop(&pb->planb_base->ch2);
2264 planb_dbdma_stop(&pb->planb_base->ch1);
2266 /* clear and free interrupts */
2267 pb->intr_mask = PLANB_CLR_IRQ;
2268 out_le32 (&pb->planb_base->intr_stat, PLANB_CLR_IRQ);
2269 free_irq(pb->irq, pb);
2271 /* make sure all allocated memory are freed */
2272 planb_prepare_close(pb);
2274 printk(KERN_INFO "PlanB: unregistering with v4l\n");
2275 video_unregister_device(&pb->video_dev);
2277 pci_dev_put(pb->dev);
2279 /* note that iounmap() does nothing on the PPC right now */
2280 iounmap ((void *)pb->planb_base);
2284 static int __init init_planbs(void)
2286 int i;
2288 if (find_planb()<=0)
2289 return -EIO;
2291 for (i=0; i<planb_num; i++) {
2292 if (init_planb(&planbs[i])<0) {
2293 printk(KERN_ERR "PlanB: error registering device %d"
2294 " with v4l\n", i);
2295 release_planb();
2296 return -EIO;
2298 printk(KERN_INFO "PlanB: registered device %d with v4l\n", i);
2300 return 0;
2303 static void __exit exit_planbs(void)
2305 release_planb();
2308 module_init(init_planbs);
2309 module_exit(exit_planbs);