Merge git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
[sfrench/cifs-2.6.git] / drivers / media / video / planb.c
1 /* 
2     planb - PlanB frame grabber driver
3
4     PlanB is used in the 7x00/8x00 series of PowerMacintosh
5     Computers as video input DMA controller.
6
7     Copyright (C) 1998 Michel Lanners (mlan@cpu.lu)
8
9     Based largely on the bttv driver by Ralph Metzler (rjkm@thp.uni-koeln.de)
10
11     Additional debugging and coding by Takashi Oe (toe@unlserve.unl.edu)
12
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.
17
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.
22
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.
26 */
27
28 /* $Id: planb.c,v 1.18 1999/05/02 17:36:34 mlan Exp $ */
29
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 <linux/wait.h>
44 #include <asm/uaccess.h>
45 #include <asm/io.h>
46 #include <asm/prom.h>
47 #include <asm/dbdma.h>
48 #include <asm/pgtable.h>
49 #include <asm/page.h>
50 #include <asm/irq.h>
51 #include <linux/mutex.h>
52
53 #include "planb.h"
54 #include "saa7196.h"
55
56 /* Would you mind for some ugly debugging? */
57 #if 0
58 #define DEBUG(x...) printk(KERN_DEBUG ## x) /* Debug driver */
59 #else
60 #define DEBUG(x...)             /* Don't debug driver */
61 #endif
62
63 #if 0
64 #define IDEBUG(x...) printk(KERN_DEBUG ## x) /* Debug interrupt part */
65 #else
66 #define IDEBUG(x...)            /* Don't debug interrupt part */
67 #endif
68
69 /* Ever seen a Mac with more than 1 of these? */
70 #define PLANB_MAX 1
71
72 static int planb_num;
73 static struct planb planbs[PLANB_MAX];
74 static volatile struct planb_registers *planb_regs;
75
76 static int def_norm = PLANB_DEF_NORM;   /* default norm */
77 static int video_nr = -1;
78
79 module_param(def_norm, int, 0);
80 MODULE_PARM_DESC(def_norm, "Default startup norm (0=PAL, 1=NTSC, 2=SECAM)");
81 module_param(video_nr, int, 0);
82 MODULE_LICENSE("GPL");
83
84
85 /* ------------------ PlanB Exported Functions ------------------ */
86 static long planb_write(struct video_device *, const char *, unsigned long, int);
87 static long planb_read(struct video_device *, char *, unsigned long, int);
88 static int planb_open(struct video_device *, int);
89 static void planb_close(struct video_device *);
90 static int planb_ioctl(struct video_device *, unsigned int, void *);
91 static int planb_init_done(struct video_device *);
92 static int planb_mmap(struct video_device *, const char *, unsigned long);
93 static void planb_irq(int, void *, struct pt_regs *);
94 static void release_planb(void);
95 int init_planbs(struct video_init *);
96
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 *);
126
127 /*******************************/
128 /* Memory management functions */
129 /*******************************/
130
131 static int grabbuf_alloc(struct planb *pb)
132 {
133         int i, npage;
134
135         npage = MAX_GBUFFERS * ((PLANB_MAX_FBUF / PAGE_SIZE + 1)
136 #ifndef PLANB_GSCANLINE
137                 + MAX_LNUM
138 #endif /* PLANB_GSCANLINE */
139                 );
140         if ((pb->rawbuf = (unsigned char**) 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]));
149         }
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);
155                 }
156                 kfree(pb->rawbuf);
157                 return -ENOBUFS;
158         }
159         pb->rawbuf_size = npage;
160         return 0;
161 }
162
163 /*****************************/
164 /* Hardware access functions */
165 /*****************************/
166
167 static void saa_write_reg(unsigned char addr, unsigned char val)
168 {
169         planb_regs->saa_addr = addr; eieio();
170         planb_regs->saa_regval = val; eieio();
171         return;
172 }
173
174 /* return  status byte 0 or 1: */
175 static unsigned char saa_status(int byte, struct planb *pb)
176 {
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]);
180
181         /* Let's wait 30msec for this one */
182         msleep_interruptible(30);
183
184         return (unsigned char)in_8 (&planb_regs->saa_status);
185 }
186
187 static void saa_set(unsigned char addr, unsigned char val, struct planb *pb)
188 {
189         if(saa_regs[pb->win.norm][addr] != val) {
190                 saa_regs[pb->win.norm][addr] = val;
191                 saa_write_reg (addr, val);
192         }
193         return;
194 }
195
196 static void saa_init_regs(struct planb *pb)
197 {
198         int i;
199
200         for (i = 0; i < SAA7196_NUMREGS; i++)
201                 saa_write_reg (i, saa_regs[pb->win.norm][i]);
202 }
203
204 static unsigned int saa_geo_setup(int width, int height, int interlace, int bpp,
205         struct planb *pb)
206 {
207         int ht, norm = pb->win.norm;
208
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;
222         }
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;
236
237         return 0;
238 }
239
240 /***************************/
241 /* DBDMA support functions */
242 /***************************/
243
244 static inline void planb_dbdma_restart(volatile struct dbdma_regs *ch)
245 {
246         out_le32(&ch->control, PLANB_CLR(RUN));
247         out_le32(&ch->control, PLANB_SET(RUN|WAKE) | PLANB_CLR(PAUSE));
248 }
249
250 static inline void planb_dbdma_stop(volatile struct dbdma_regs *ch)
251 {
252         int i = 0;
253
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++;
258         }
259 }
260
261 static inline void tab_cmd_dbdma(volatile struct dbdma_cmd *ch,
262         unsigned short command, unsigned int cmd_dep)
263 {
264         st_le16(&ch->command, command);
265         st_le32(&ch->cmd_dep, cmd_dep);
266 }
267
268 static inline void tab_cmd_store(volatile struct dbdma_cmd *ch,
269         unsigned int phy_addr, unsigned int cmd_dep)
270 {
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);
275 }
276
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)
280 {
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);
285 }
286
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)
290 {
291         int norm = pb->win.norm;
292
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;
324 }
325
326 /******************************/
327 /* misc. supporting functions */
328 /******************************/
329
330 static inline void planb_lock(struct planb *pb)
331 {
332         mutex_lock(&pb->lock);
333 }
334
335 static inline void planb_unlock(struct planb *pb)
336 {
337         mutex_unlock(&pb->lock);
338 }
339
340 /***************/
341 /* Driver Core */
342 /***************/
343
344 static int planb_prepare_open(struct planb *pb)
345 {
346         int     i, size;
347
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;
367         }
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);
371
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 */
385         }
386         pb->gcount = 0;
387         pb->suspend = 0;
388         pb->last_fr = -999;
389         pb->prev_last_fr = -999;
390
391         /* Reset DMA controllers */
392         planb_dbdma_stop(&pb->planb_base->ch2);
393         planb_dbdma_stop(&pb->planb_base->ch1);
394
395         return 0;
396 }
397
398 static void planb_prepare_close(struct planb *pb)
399 {
400         int i;
401
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;
410         }
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);
415                 }
416                 kfree(pb->rawbuf);
417         }
418         pb->rawbuf = NULL;
419 }
420
421 /*****************************/
422 /* overlay support functions */
423 /*****************************/
424
425 static inline int overlay_is_active(struct planb *pb)
426 {
427         unsigned int size = pb->tab_size * sizeof(struct dbdma_cmd);
428         unsigned int caddr = (unsigned)in_le32(&pb->planb_base->ch1.cmdptr);
429
430         return (in_le32(&pb->overlay_last1->cmd_dep) == pb->ch1_cmd_phys)
431                         && (caddr < (pb->ch1_cmd_phys + size))
432                         && (caddr >= (unsigned)pb->ch1_cmd_phys);
433 }
434
435 static void overlay_start(struct planb *pb)
436 {
437
438         DEBUG("PlanB: overlay_start()\n");
439
440         if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) {
441
442                 DEBUG("PlanB: presumably, grabbing is in progress...\n");
443
444                 planb_dbdma_stop(&pb->planb_base->ch2);
445                 out_le32 (&pb->planb_base->ch2.cmdptr,
446                                                 virt_to_bus(pb->ch2_cmd));
447                 planb_dbdma_restart(&pb->planb_base->ch2);
448                 st_le16 (&pb->ch1_cmd->command, DBDMA_NOP);
449                 tab_cmd_dbdma(pb->last_cmd[pb->last_fr],
450                                         DBDMA_NOP | BR_ALWAYS,
451                                         virt_to_bus(pb->ch1_cmd));
452                 eieio();
453                 pb->prev_last_fr = pb->last_fr;
454                 pb->last_fr = -2;
455                 if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) {
456                         IDEBUG("PlanB: became inactive "
457                                 "in the mean time... reactivating\n");
458                         planb_dbdma_stop(&pb->planb_base->ch1);
459                         out_le32 (&pb->planb_base->ch1.cmdptr,
460                                                 virt_to_bus(pb->ch1_cmd));
461                         planb_dbdma_restart(&pb->planb_base->ch1);
462                 }
463         } else {
464
465                 DEBUG("PlanB: currently idle, so can do whatever\n");
466
467                 planb_dbdma_stop(&pb->planb_base->ch2);
468                 planb_dbdma_stop(&pb->planb_base->ch1);
469                 st_le32 (&pb->planb_base->ch2.cmdptr,
470                                                 virt_to_bus(pb->ch2_cmd));
471                 st_le32 (&pb->planb_base->ch1.cmdptr,
472                                                 virt_to_bus(pb->ch1_cmd));
473                 out_le16 (&pb->ch1_cmd->command, DBDMA_NOP);
474                 planb_dbdma_restart(&pb->planb_base->ch2);
475                 planb_dbdma_restart(&pb->planb_base->ch1);
476                 pb->last_fr = -1;
477         }
478         return;
479 }
480
481 static void overlay_stop(struct planb *pb)
482 {
483         DEBUG("PlanB: overlay_stop()\n");
484
485         if(pb->last_fr == -1) {
486
487                 DEBUG("PlanB: no grabbing, it seems...\n");
488
489                 planb_dbdma_stop(&pb->planb_base->ch2);
490                 planb_dbdma_stop(&pb->planb_base->ch1);
491                 pb->last_fr = -999;
492         } else if(pb->last_fr == -2) {
493                 unsigned int cmd_dep;
494                 tab_cmd_dbdma(pb->cap_cmd[pb->prev_last_fr], DBDMA_STOP, 0);
495                 eieio();
496                 cmd_dep = (unsigned int)in_le32(&pb->overlay_last1->cmd_dep);
497                 if(overlay_is_active(pb)) {
498
499                         DEBUG("PlanB: overlay is currently active\n");
500
501                         planb_dbdma_stop(&pb->planb_base->ch2);
502                         planb_dbdma_stop(&pb->planb_base->ch1);
503                         if(cmd_dep != pb->ch1_cmd_phys) {
504                                 out_le32(&pb->planb_base->ch1.cmdptr,
505                                                 virt_to_bus(pb->overlay_last1));
506                                 planb_dbdma_restart(&pb->planb_base->ch1);
507                         }
508                 }
509                 pb->last_fr = pb->prev_last_fr;
510                 pb->prev_last_fr = -999;
511         }
512         return;
513 }
514
515 static void suspend_overlay(struct planb *pb)
516 {
517         int fr = -1;
518         struct dbdma_cmd last;
519
520         DEBUG("PlanB: suspend_overlay: %d\n", pb->suspend);
521
522         if(pb->suspend++)
523                 return;
524         if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) {
525                 if(pb->last_fr == -2) {
526                         fr = pb->prev_last_fr;
527                         memcpy(&last, (void*)pb->last_cmd[fr], sizeof(last));
528                         tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0);
529                 }
530                 if(overlay_is_active(pb)) {
531                         planb_dbdma_stop(&pb->planb_base->ch2);
532                         planb_dbdma_stop(&pb->planb_base->ch1);
533                         pb->suspended.overlay = 1;
534                         pb->suspended.frame = fr;
535                         memcpy(&pb->suspended.cmd, &last, sizeof(last));
536                         return;
537                 }
538         }
539         pb->suspended.overlay = 0;
540         pb->suspended.frame = fr;
541         memcpy(&pb->suspended.cmd, &last, sizeof(last));
542         return;
543 }
544
545 static void resume_overlay(struct planb *pb)
546 {
547
548         DEBUG("PlanB: resume_overlay: %d\n", pb->suspend);
549
550         if(pb->suspend > 1)
551                 return;
552         if(pb->suspended.frame != -1) {
553                 memcpy((void*)pb->last_cmd[pb->suspended.frame],
554                                 &pb->suspended.cmd, sizeof(pb->suspended.cmd));
555         }
556         if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) {
557                 goto finish;
558         }
559         if(pb->suspended.overlay) {
560
561                 DEBUG("PlanB: overlay being resumed\n");
562
563                 st_le16 (&pb->ch1_cmd->command, DBDMA_NOP);
564                 st_le16 (&pb->ch2_cmd->command, DBDMA_NOP);
565                 /* Set command buffer addresses */
566                 st_le32(&pb->planb_base->ch1.cmdptr,
567                                         virt_to_bus(pb->overlay_last1));
568                 out_le32(&pb->planb_base->ch2.cmdptr,
569                                         virt_to_bus(pb->overlay_last2));
570                 /* Start the DMA controller */
571                 out_le32 (&pb->planb_base->ch2.control,
572                                 PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE));
573                 out_le32 (&pb->planb_base->ch1.control,
574                                 PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE));
575         } else if(pb->suspended.frame != -1) {
576                 out_le32(&pb->planb_base->ch1.cmdptr,
577                                 virt_to_bus(pb->last_cmd[pb->suspended.frame]));
578                 out_le32 (&pb->planb_base->ch1.control,
579                                 PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE));
580         }
581
582 finish:
583         pb->suspend--;
584         wake_up_interruptible(&pb->suspendq);
585 }
586
587 static void add_clip(struct planb *pb, struct video_clip *clip) 
588 {
589         volatile unsigned char  *base;
590         int     xc = clip->x, yc = clip->y;
591         int     wc = clip->width, hc = clip->height;
592         int     ww = pb->win.width, hw = pb->win.height;
593         int     x, y, xtmp1, xtmp2;
594
595         DEBUG("PlanB: clip %dx%d+%d+%d\n", wc, hc, xc, yc);
596
597         if(xc < 0) {
598                 wc += xc;
599                 xc = 0;
600         }
601         if(yc < 0) {
602                 hc += yc;
603                 yc = 0;
604         }
605         if(xc + wc > ww)
606                 wc = ww - xc;
607         if(wc <= 0) /* Nothing to do */
608                 return;
609         if(yc + hc > hw)
610                 hc = hw - yc;
611
612         for (y = yc; y < yc+hc; y++) {
613                 xtmp1=xc>>3;
614                 xtmp2=(xc+wc)>>3;
615                 base = pb->mask + y*96;
616                 if(xc != 0 || wc >= 8)
617                         *(base + xtmp1) &= (unsigned char)(0x00ff &
618                                 (0xff00 >> (xc&7)));
619                 for (x = xtmp1 + 1; x < xtmp2; x++) {
620                         *(base + x) = 0;
621                 }
622                 if(xc < (ww & ~0x7))
623                         *(base + xtmp2) &= (unsigned char)(0x00ff >>
624                                 ((xc+wc) & 7));
625         }
626
627         return;
628 }
629
630 static void fill_cmd_buff(struct planb *pb)
631 {
632         int restore = 0;
633         volatile struct dbdma_cmd last;
634
635         DEBUG("PlanB: fill_cmd_buff()\n");
636
637         if(pb->overlay_last1 != pb->ch1_cmd) {
638                 restore = 1;
639                 last = *(pb->overlay_last1);
640         }
641         memset ((void *) pb->ch1_cmd, 0, 2 * pb->tab_size
642                                         * sizeof(struct dbdma_cmd));
643         cmd_buff (pb);
644         if(restore)
645                 *(pb->overlay_last1) = last;
646         if(pb->suspended.overlay) {
647                 unsigned long jump_addr = in_le32(&pb->overlay_last1->cmd_dep);
648                 if(jump_addr != pb->ch1_cmd_phys) {
649                         int i;
650
651                         DEBUG("PlanB: adjusting ch1's jump address\n");
652
653                         for(i = 0; i < MAX_GBUFFERS; i++) {
654                                 if(pb->need_pre_capture[i]) {
655                                     if(jump_addr == virt_to_bus(pb->pre_cmd[i]))
656                                         goto found;
657                                 } else {
658                                     if(jump_addr == virt_to_bus(pb->cap_cmd[i]))
659                                         goto found;
660                                 }
661                         }
662
663                         DEBUG("PlanB: not found...\n");
664
665                         goto out;
666 found:
667                         if(pb->need_pre_capture[i])
668                                 out_le32(&pb->pre_cmd[i]->phy_addr,
669                                                 virt_to_bus(pb->overlay_last1));
670                         else
671                                 out_le32(&pb->cap_cmd[i]->phy_addr,
672                                                 virt_to_bus(pb->overlay_last1));
673                 }
674         }
675 out:
676         pb->cmd_buff_inited = 1;
677
678         return;
679 }
680
681 static void cmd_buff(struct planb *pb)
682 {
683         int             i, bpp, count, nlines, stepsize, interlace;
684         unsigned long   base, jump, addr_com, addr_dep;
685         volatile struct dbdma_cmd *c1 = pb->ch1_cmd;
686         volatile struct dbdma_cmd *c2 = pb->ch2_cmd;
687
688         interlace = pb->win.interlace;
689         bpp = pb->win.bpp;
690         count = (bpp * ((pb->win.x + pb->win.width > pb->win.swidth) ?
691                 (pb->win.swidth - pb->win.x) : pb->win.width));
692         nlines = ((pb->win.y + pb->win.height > pb->win.sheight) ?
693                 (pb->win.sheight - pb->win.y) : pb->win.height);
694
695         /* Do video in: */
696
697         /* Preamble commands: */
698         addr_com = virt_to_bus(c1);
699         addr_dep = virt_to_bus(&c1->cmd_dep);
700         tab_cmd_dbdma(c1++, DBDMA_NOP, 0);
701         jump = virt_to_bus(c1+16); /* 14 by cmd_geo_setup() and 2 for padding */
702         if((c1 = cmd_geo_setup(c1, pb->win.width, pb->win.height, interlace,
703                                         bpp, 1, pb)) == NULL) {
704                 printk(KERN_WARNING "PlanB: encountered serious problems\n");
705                 tab_cmd_dbdma(pb->ch1_cmd + 1, DBDMA_STOP, 0);
706                 tab_cmd_dbdma(pb->ch2_cmd + 1, DBDMA_STOP, 0);
707                 return;
708         }
709         tab_cmd_store(c1++, addr_com, (unsigned)(DBDMA_NOP | BR_ALWAYS) << 16);
710         tab_cmd_store(c1++, addr_dep, jump);
711         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel),
712                                                         PLANB_SET(FIELD_SYNC));
713                 /* (1) wait for field sync to be set */
714         tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
715         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
716                                                         PLANB_SET(ODD_FIELD));
717                 /* wait for field sync to be cleared */
718         tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
719                 /* if not odd field, wait until field sync is set again */
720         tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++;
721                 /* assert ch_sync to ch2 */
722         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch2.control),
723                                                         PLANB_SET(CH_SYNC));
724         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
725                                                         PLANB_SET(DMA_ABORT));
726
727         base = (pb->frame_buffer_phys + pb->offset + pb->win.y * (pb->win.bpl
728                                         + pb->win.pad) + pb->win.x * bpp);
729
730         if (interlace) {
731                 stepsize = 2;
732                 jump = virt_to_bus(c1 + (nlines + 1) / 2);
733         } else {
734                 stepsize = 1;
735                 jump = virt_to_bus(c1 + nlines);
736         }
737
738         /* even field data: */
739         for (i=0; i < nlines; i += stepsize, c1++)
740                 tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET,
741                         count, base + i * (pb->win.bpl + pb->win.pad), jump);
742
743         /* For non-interlaced, we use even fields only */
744         if (!interlace)
745                 goto cmd_tab_data_end;
746
747         /* Resync to odd field */
748                 /* (2) wait for field sync to be set */
749         tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
750         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
751                                                         PLANB_SET(ODD_FIELD));
752                 /* wait for field sync to be cleared */
753         tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
754                 /* if not odd field, wait until field sync is set again */
755         tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++;
756                 /* assert ch_sync to ch2 */
757         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch2.control),
758                                                         PLANB_SET(CH_SYNC));
759         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
760                                                         PLANB_SET(DMA_ABORT));
761         
762         /* odd field data: */
763         jump = virt_to_bus(c1 + nlines / 2);
764         for (i=1; i < nlines; i += stepsize, c1++)
765                 tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count,
766                         base + i * (pb->win.bpl + pb->win.pad), jump);
767
768         /* And jump back to the start */
769 cmd_tab_data_end:
770         pb->overlay_last1 = c1; /* keep a pointer to the last command */
771         tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->ch1_cmd));
772
773         /* Clipmask command buffer */
774
775         /* Preamble commands: */
776         tab_cmd_dbdma(c2++, DBDMA_NOP, 0);
777         tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.wait_sel),
778                                                         PLANB_SET(CH_SYNC));
779                 /* wait until ch1 asserts ch_sync */
780         tab_cmd_dbdma(c2++, DBDMA_NOP | WAIT_IFCLR, 0);
781                 /* clear ch_sync asserted by ch1 */
782         tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.control),
783                                                         PLANB_CLR(CH_SYNC));
784         tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.wait_sel),
785                                                         PLANB_SET(FIELD_SYNC));
786         tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel),
787                                                         PLANB_SET(ODD_FIELD));
788
789         /* jump to end of even field if appropriate */
790         /* this points to (interlace)? pos. C: pos. B */
791         jump = (interlace) ? virt_to_bus(c2 + (nlines + 1) / 2 + 2):
792                                                 virt_to_bus(c2 + nlines + 2);
793                 /* if odd field, skip over to odd field clipmasking */
794         tab_cmd_dbdma(c2++, DBDMA_NOP | BR_IFSET, jump);
795
796         /* even field mask: */
797         tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel),
798                                                         PLANB_SET(DMA_ABORT));
799         /* this points to pos. B */
800         jump = (interlace) ? virt_to_bus(c2 + nlines + 1):
801                                                 virt_to_bus(c2 + nlines);
802         base = virt_to_bus(pb->mask);
803         for (i=0; i < nlines; i += stepsize, c2++)
804                 tab_cmd_gen(c2, OUTPUT_MORE | KEY_STREAM0 | BR_IFSET, 96,
805                         base + i * 96, jump);
806
807         /* For non-interlaced, we use only even fields */
808         if(!interlace)
809                 goto cmd_tab_mask_end;
810
811         /* odd field mask: */
812 /* C */ tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel),
813                                                         PLANB_SET(DMA_ABORT));
814         /* this points to pos. B */
815         jump = virt_to_bus(c2 + nlines / 2);
816         base = virt_to_bus(pb->mask);
817         for (i=1; i < nlines; i += 2, c2++)     /* abort if set */
818                 tab_cmd_gen(c2, OUTPUT_MORE | KEY_STREAM0 | BR_IFSET, 96,
819                         base + i * 96, jump);
820
821         /* Inform channel 1 and jump back to start */
822 cmd_tab_mask_end:
823         /* ok, I just realized this is kind of flawed. */
824         /* this part is reached only after odd field clipmasking. */
825         /* wanna clean up? */
826                 /* wait for field sync to be set */
827                 /* corresponds to fsync (1) of ch1 */
828 /* B */ tab_cmd_dbdma(c2++, DBDMA_NOP | WAIT_IFCLR, 0);
829                 /* restart ch1, meant to clear any dead bit or something */
830         tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch1.control),
831                                                         PLANB_CLR(RUN));
832         tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch1.control),
833                                                         PLANB_SET(RUN));
834         pb->overlay_last2 = c2; /* keep a pointer to the last command */
835                 /* start over even field clipmasking */
836         tab_cmd_dbdma(c2, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->ch2_cmd));
837
838         eieio();
839         return;
840 }
841
842 /*********************************/
843 /* grabdisplay support functions */
844 /*********************************/
845
846 static int palette2fmt[] = {
847        0,
848        PLANB_GRAY,
849        0,
850        0,
851        0,
852        PLANB_COLOUR32,
853        PLANB_COLOUR15,
854        0,
855        0,
856        0,
857        0,
858        0,
859        0,
860        0,
861        0,
862 };
863
864 #define PLANB_PALETTE_MAX 15
865
866 static int vgrab(struct planb *pb, struct video_mmap *mp)
867 {
868         unsigned int fr = mp->frame;
869         unsigned int format;
870
871         if(pb->rawbuf==NULL) {
872                 int err;
873                 if((err=grabbuf_alloc(pb)))
874                         return err;
875         }
876
877         IDEBUG("PlanB: grab %d: %dx%d(%u)\n", pb->grabbing,
878                                                 mp->width, mp->height, fr);
879
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;
892
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
902
903                 IDEBUG("PlanB: gwidth = %d, gheight = %d, mp->format = %u\n",
904                                         mp->width, mp->height, mp->format);
905
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;
913                         }
914                 }
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 */
920 /*
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
929                         }
930                 }
931 */
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))) {
944
945                 IDEBUG("PlanB: ch1 inactive, initiating grabbing\n");
946
947                 planb_dbdma_stop(&pb->planb_base->ch1);
948                 if(pb->need_pre_capture[fr]) {
949
950                         IDEBUG("PlanB: padding pre-capture sequence\n");
951
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]));
961                 }
962                 planb_dbdma_restart(&pb->planb_base->ch1);
963                 pb->last_fr = fr;
964         } else {
965                 int i;
966
967                 IDEBUG("PlanB: ch1 active, grabbing being queued\n");
968
969                 if((pb->last_fr == -1) || ((pb->last_fr == -2) &&
970                                                 overlay_is_active(pb))) {
971
972                         IDEBUG("PlanB: overlay is active, grabbing defered\n");
973
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]) {
978
979                                 IDEBUG("PlanB: padding pre-capture sequence\n");
980
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]));
996                         }
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) {
1003
1004                         IDEBUG("PlanB: mixed mode detected, grabbing"
1005                                 " will be done before activating overlay\n");
1006
1007                         tab_cmd_dbdma(pb->ch1_cmd, DBDMA_NOP, 0);
1008                         if(pb->need_pre_capture[fr]) {
1009
1010                                 IDEBUG("PlanB: padding pre-capture sequence\n");
1011
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();
1034                         }
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 {
1042
1043                         IDEBUG("PlanB: active grabbing session detected\n");
1044
1045                         if(pb->need_pre_capture[fr]) {
1046
1047                                 IDEBUG("PlanB: padding pre-capture sequence\n");
1048
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();
1071                         }
1072                         pb->last_fr = fr;
1073                 }
1074                 if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) {
1075
1076                         IDEBUG("PlanB: became inactive in the mean time..."
1077                                 "reactivating\n");
1078
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);
1083                 }
1084         }
1085         pb->grabbing++;
1086         planb_unlock(pb);
1087
1088         return 0;
1089 }
1090
1091 static void planb_pre_capture(int fr, int bpp, struct planb *pb)
1092 {
1093         volatile struct dbdma_cmd *c1 = pb->pre_cmd[fr];
1094         int interlace = (pb->gheight[fr] > pb->maxlines/2)? 1: 0;
1095
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;
1102         }
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]));
1127
1128         eieio();
1129 }
1130
1131 static volatile struct dbdma_cmd *setup_grab_cmd(int fr, struct planb *pb)
1132 {
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;
1144
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
1156
1157         /* Do video in: */
1158
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);
1167         }
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));
1178
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;
1185         }
1186         jump = virt_to_bus(jump_addr);
1187
1188         /* even field data: */
1189
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);
1196         }
1197 #else
1198         i = 0;
1199         leftover1 = 0;
1200         do {
1201             int j;
1202
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;
1210
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]--;
1227                     }
1228                     leftover1 = count * stepsize - lov0;
1229                     i += stepsize;
1230                 }
1231             }
1232             pagei++;
1233         } while(i < nlines);
1234         tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, jump);
1235         c1 = jump_addr;
1236 #endif /* PLANB_GSCANLINE */
1237
1238         /* For non-interlaced, we use even fields only */
1239         if (!interlace)
1240                 goto cmd_tab_data_end;
1241
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));
1250         
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);
1259         }
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;
1268
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;
1275             }
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;
1281
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;
1297                     }
1298                     leftover1 = count * stepsize - lov0;
1299                 }
1300             }
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 */
1307
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);
1313
1314         eieio();
1315         return c1;
1316 }
1317
1318 static void planb_irq(int irq, void *dev_id, struct pt_regs * regs)
1319 {
1320         unsigned int stat, astat;
1321         struct planb *pb = (struct planb *)dev_id;
1322
1323         IDEBUG("PlanB: planb_irq()\n");
1324
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);
1332
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");
1339
1340                 pb->gcount++;
1341
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];
1349
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]);
1356                 }
1357 #endif
1358                 pb->frame_stat[fr] = GBUFFER_DONE;
1359                 pb->grabbing--;
1360                 wake_up_interruptible(&pb->capq);
1361                 return;
1362         }
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");
1368 }
1369
1370 /*******************************
1371  * Device Operations functions *
1372  *******************************/
1373
1374 static int planb_open(struct video_device *dev, int mode)
1375 {
1376         struct planb *pb = (struct planb *)dev;
1377
1378         if (pb->user == 0) {
1379                 int err;
1380                 if((err = planb_prepare_open(pb)) != 0)
1381                         return err;
1382         }
1383         pb->user++;
1384
1385         DEBUG("PlanB: device opened\n");
1386         return 0;   
1387 }
1388
1389 static void planb_close(struct video_device *dev)
1390 {
1391         struct planb *pb = (struct planb *)dev;
1392
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;
1401                 }
1402                 planb_prepare_close(pb);
1403         }
1404         pb->user--;
1405         planb_unlock(pb);
1406
1407         DEBUG("PlanB: device closed\n");
1408 }
1409
1410 static long planb_read(struct video_device *v, char *buf, unsigned long count,
1411                                 int nonblock)
1412 {
1413         DEBUG("planb: read request\n");
1414         return -EINVAL;
1415 }
1416
1417 static long planb_write(struct video_device *v, const char *buf,
1418                                 unsigned long count, int nonblock)
1419 {
1420         DEBUG("planb: write request\n");
1421         return -EINVAL;
1422 }
1423
1424 static int planb_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
1425 {
1426         struct planb *pb=(struct planb *)dev;
1427         
1428         switch (cmd)
1429         {       
1430                 case VIDIOCGCAP:
1431                 {
1432                         struct video_capability b;
1433
1434                         DEBUG("PlanB: IOCTL VIDIOCGCAP\n");
1435
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;
1449                 }
1450                 case VIDIOCSFBUF:
1451                 {
1452                         struct video_buffer v;
1453                         unsigned short bpp;
1454                         unsigned int fmt;
1455
1456                         DEBUG("PlanB: IOCTL VIDIOCSFBUF\n");
1457
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;
1482                         }
1483                         if (bpp * v.width > v.bytesperline) {
1484                                 planb_unlock(pb);
1485                                 return -EINVAL;
1486                         }
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;
1495
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);
1499
1500                         pb->cmd_buff_inited = 0;
1501                         if(pb->overlay) {
1502                                 suspend_overlay(pb);
1503                                 fill_cmd_buff(pb);
1504                                 resume_overlay(pb);
1505                         }
1506                         planb_unlock(pb);
1507                         return 0;               
1508                 }
1509                 case VIDIOCGFBUF:
1510                 {
1511                         struct video_buffer v;
1512
1513                         DEBUG("PlanB: IOCTL VIDIOCGFBUF\n");
1514
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;
1523                 }
1524                 case VIDIOCCAPTURE:
1525                 {
1526                         int i;
1527
1528                         if(copy_from_user(&i, arg, sizeof(i)))
1529                                 return -EFAULT;
1530                         if(i==0) {
1531                                 DEBUG("PlanB: IOCTL VIDIOCCAPTURE Stop\n");
1532
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");
1541
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);
1554                         }
1555                         return 0;
1556                 }
1557                 case VIDIOCGCHAN:
1558                 {
1559                         struct video_channel v;
1560
1561                         DEBUG("PlanB: IOCTL VIDIOCGCHAN\n");
1562
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)
1570                         {
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;
1580                         }
1581                         if(copy_to_user(arg,&v,sizeof(v)))
1582                                 return -EFAULT;
1583
1584                         return 0;
1585                 }
1586                 case VIDIOCSCHAN:
1587                 {
1588                         struct video_channel v;
1589
1590                         DEBUG("PlanB: IOCTL VIDIOCSCHAN\n");
1591
1592                         if(copy_from_user(&v, arg, sizeof(v)))
1593                                 return -EFAULT;
1594
1595                         if (v.norm != pb->win.norm) {
1596                                 int i, maxlines;
1597
1598                                 switch (v.norm)
1599                                 {
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;
1610                                 }
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);
1627                         }
1628
1629                         switch(v.channel)
1630                         {
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;
1644                         }
1645
1646                         return 0;
1647                 }
1648                 case VIDIOCGPICT:
1649                 {
1650                         struct video_picture vp = pb->picture;
1651
1652                         DEBUG("PlanB: IOCTL VIDIOCGPICT\n");
1653
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;
1666                         }
1667
1668                         if(copy_to_user(arg,&vp,sizeof(vp)))
1669                                 return -EFAULT;
1670                         return 0;
1671                 }
1672                 case VIDIOCSPICT:
1673                 {
1674                         struct video_picture vp;
1675
1676                         DEBUG("PlanB: IOCTL VIDIOCSPICT\n");
1677
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);
1690
1691                         return 0;
1692                 }
1693                 case VIDIOCSWIN:
1694                 {
1695                         struct video_window     vw;
1696                         struct video_clip       clip;
1697                         int                     i;
1698                         
1699                         DEBUG("PlanB: IOCTL VIDIOCSWIN\n");
1700
1701                         if(copy_from_user(&vw,arg,sizeof(vw)))
1702                                 return -EFAULT;
1703
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);
1718                         }
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);
1728                         }
1729                         /* restart overlay if it was running */
1730                         resume_overlay(pb);
1731                         planb_unlock(pb);
1732                         return 0;
1733                 }
1734                 case VIDIOCGWIN:
1735                 {
1736                         struct video_window vw;
1737
1738                         DEBUG("PlanB: IOCTL VIDIOCGWIN\n");
1739
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;
1751                 }
1752                 case VIDIOCSYNC: {
1753                         int i;
1754
1755                         IDEBUG("PlanB: IOCTL VIDIOCSYNC\n");
1756
1757                         if(copy_from_user((void *)&i,arg,sizeof(int)))
1758                                 return -EFAULT;
1759
1760                         IDEBUG("PlanB: sync to frame %d\n", i);
1761
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;
1778                         }
1779                         return 0;
1780                 }
1781
1782                 case VIDIOCMCAPTURE:
1783                 {
1784                         struct video_mmap vm;
1785                         volatile unsigned int status;
1786
1787                         IDEBUG("PlanB: IOCTL VIDIOCMCAPTURE\n");
1788
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;
1794
1795                         return vgrab(pb, &vm);
1796                 }
1797                 
1798                 case VIDIOCGMBUF:
1799                 {
1800                         int i;
1801                         struct video_mbuf vm;
1802
1803                         DEBUG("PlanB: IOCTL VIDIOCGMBUF\n");
1804
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;
1813                 }
1814                 
1815                 case PLANBIOCGSAAREGS:
1816                 {
1817                         struct planb_saa_regs preg;
1818
1819                         DEBUG("PlanB: IOCTL PLANBIOCGSAAREGS\n");
1820
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;
1830                 }
1831                 
1832                 case PLANBIOCSSAAREGS:
1833                 {
1834                         struct planb_saa_regs preg;
1835
1836                         DEBUG("PlanB: IOCTL PLANBIOCSSAAREGS\n");
1837
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;
1844                 }
1845                 
1846                 case PLANBIOCGSTAT:
1847                 {
1848                         struct planb_stat_regs pstat;
1849
1850                         DEBUG("PlanB: IOCTL PLANBIOCGSTAT\n");
1851
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);
1856
1857                         if(copy_to_user((void *)arg, (void *)&pstat,
1858                                                         sizeof(pstat)))
1859                                 return -EFAULT;
1860                         return 0;
1861                 }
1862                 
1863                 case PLANBIOCSMODE: {
1864                         int v;
1865
1866                         DEBUG("PlanB: IOCTL PLANBIOCSMODE\n");
1867
1868                         if(copy_from_user(&v, arg, sizeof(v)))
1869                                 return -EFAULT;
1870
1871                         switch(v)
1872                         {
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;
1886                         }
1887                         pb->win.mode = v;
1888                         return 0;
1889                 }
1890                 case PLANBIOCGMODE: {
1891                         int v=pb->win.mode;
1892
1893                         DEBUG("PlanB: IOCTL PLANBIOCGMODE\n");
1894
1895                         if(copy_to_user(arg,&v,sizeof(v)))
1896                                 return -EFAULT;
1897                         return 0;
1898                 }
1899 #ifdef PLANB_GSCANLINE
1900                 case PLANBG_GRAB_BPL: {
1901                         int v=pb->gbytes_per_line;
1902
1903                         DEBUG("PlanB: IOCTL PLANBG_GRAB_BPL\n");
1904
1905                         if(copy_to_user(arg,&v,sizeof(v)))
1906                                 return -EFAULT;
1907                         return 0;
1908                 }
1909 #endif /* PLANB_GSCANLINE */
1910                 case PLANB_INTR_DEBUG: {
1911                         int i;
1912
1913                         DEBUG("PlanB: IOCTL PLANB_INTR_DEBUG\n");
1914
1915                         if(copy_from_user(&i, arg, sizeof(i)))
1916                                 return -EFAULT;
1917
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;
1922                                 }
1923                         }
1924                         if(pb->grabbing)
1925                                 pb->grabbing--;
1926                         wake_up_interruptible(&pb->capq);
1927                         return 0;
1928                 }
1929                 case PLANB_INV_REGS: {
1930                         int i;
1931                         struct planb_any_regs any;
1932
1933                         DEBUG("PlanB: IOCTL PLANB_INV_REGS\n");
1934
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);
1945                         }
1946                         if(copy_to_user(arg,&any,sizeof(any)))
1947                                 return -EFAULT;
1948                         return 0;
1949                 }
1950                 default:
1951                 {
1952                         DEBUG("PlanB: Unimplemented IOCTL\n");
1953                         return -ENOIOCTLCMD;
1954                 }
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;
1980         }
1981         return 0;
1982 }
1983
1984 static int planb_mmap(struct vm_area_struct *vma, struct video_device *dev, const char *adr, unsigned long size)
1985 {
1986         int i;
1987         struct planb *pb = (struct planb *)dev;
1988         unsigned long start = (unsigned long)adr;
1989
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;
1996         }
1997         for (i = 0; i < pb->rawbuf_size; i++) {
1998                 unsigned long pfn;
1999
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;
2007         }
2008         return 0;
2009 }
2010
2011 static struct video_device planb_template=
2012 {
2013         .owner          = THIS_MODULE,
2014         .name           = PLANB_DEVICE_NAME,
2015         .type           = VID_TYPE_OVERLAY,
2016         .hardware       = VID_HARDWARE_PLANB,
2017         .open           = planb_open,
2018         .close          = planb_close,
2019         .read           = planb_read,
2020         .write          = planb_write,
2021         .ioctl          = planb_ioctl,
2022         .mmap           = planb_mmap,   /* mmap? */
2023 };
2024
2025 static int init_planb(struct planb *pb)
2026 {
2027         unsigned char saa_rev;
2028         int i, result;
2029
2030         memset ((void *) &pb->win, 0, sizeof (struct planb_window));
2031         /* Simple sanity check */
2032         if(def_norm >= NUM_SUPPORTED_NORM || def_norm < 0) {
2033                 printk(KERN_ERR "PlanB: Option(s) invalid\n");
2034                 return -2;
2035         }
2036         pb->win.norm = def_norm;
2037         pb->win.mode = PLANB_TV_MODE;   /* TV mode */
2038         pb->win.interlace=1;
2039         pb->win.x=0;
2040         pb->win.y=0;
2041         pb->win.width=768; /* 640 */
2042         pb->win.height=576; /* 480 */
2043         pb->maxlines=576;
2044 #if 0
2045         btv->win.cropwidth=768; /* 640 */
2046         btv->win.cropheight=576; /* 480 */
2047         btv->win.cropx=0;
2048         btv->win.cropy=0;
2049 #endif
2050         pb->win.pad=0;
2051         pb->win.bpp=4;
2052         pb->win.depth=32;
2053         pb->win.color_fmt=PLANB_COLOUR32;
2054         pb->win.bpl=1024*pb->win.bpp;
2055         pb->win.swidth=1024;
2056         pb->win.sheight=768;
2057 #ifdef PLANB_GSCANLINE
2058         if((pb->gbytes_per_line = PLANB_MAXPIXELS * 4) > PAGE_SIZE
2059                                 || (pb->gbytes_per_line <= 0))
2060                 return -3;
2061         else {
2062                 /* page align pb->gbytes_per_line for DMA purpose */
2063                 for(i = PAGE_SIZE; pb->gbytes_per_line < (i>>1);)
2064                         i>>=1;
2065                 pb->gbytes_per_line = i;
2066         }
2067 #endif
2068         pb->tab_size = PLANB_MAXLINES + 40;
2069         pb->suspend = 0;
2070         mutex_init(&pb->lock);
2071         pb->ch1_cmd = 0;
2072         pb->ch2_cmd = 0;
2073         pb->mask = 0;
2074         pb->priv_space = 0;
2075         pb->offset = 0;
2076         pb->user = 0;
2077         pb->overlay = 0;
2078         init_waitqueue_head(&pb->suspendq);
2079         pb->cmd_buff_inited = 0;
2080         pb->frame_buffer_phys = 0;
2081
2082         /* Reset DMA controllers */
2083         planb_dbdma_stop(&pb->planb_base->ch2);
2084         planb_dbdma_stop(&pb->planb_base->ch1);
2085
2086         saa_rev =  (saa_status(0, pb) & 0xf0) >> 4;
2087         printk(KERN_INFO "PlanB: SAA7196 video processor rev. %d\n", saa_rev);
2088         /* Initialize the SAA registers in memory and on chip */
2089         saa_init_regs (pb);
2090
2091         /* clear interrupt mask */
2092         pb->intr_mask = PLANB_CLR_IRQ;
2093
2094         result = request_irq(pb->irq, planb_irq, 0, "PlanB", (void *)pb);
2095         if (result < 0) {
2096                 if (result==-EINVAL)
2097                         printk(KERN_ERR "PlanB: Bad irq number (%d) "
2098                                                 "or handler\n", (int)pb->irq);
2099                 else if (result==-EBUSY)
2100                         printk(KERN_ERR "PlanB: I don't know why, "
2101                                         "but IRQ %d is busy\n", (int)pb->irq);
2102                 return result;
2103         }
2104         disable_irq(pb->irq);
2105         
2106         /* Now add the template and register the device unit. */
2107         memcpy(&pb->video_dev,&planb_template,sizeof(planb_template));
2108
2109         pb->picture.brightness=0x90<<8;
2110         pb->picture.contrast = 0x70 << 8;
2111         pb->picture.colour = 0x70<<8;
2112         pb->picture.hue = 0x8000;
2113         pb->picture.whiteness = 0;
2114         pb->picture.depth = pb->win.depth;
2115
2116         pb->frame_stat=NULL;
2117         init_waitqueue_head(&pb->capq);
2118         for(i=0; i<MAX_GBUFFERS; i++) {
2119                 pb->gbuf_idx[i] = PLANB_MAX_FBUF * i / PAGE_SIZE;
2120                 pb->gwidth[i]=0;
2121                 pb->gheight[i]=0;
2122                 pb->gfmt[i]=0;
2123                 pb->cap_cmd[i]=NULL;
2124 #ifndef PLANB_GSCANLINE
2125                 pb->l_fr_addr_idx[i] = MAX_GBUFFERS * (PLANB_MAX_FBUF
2126                                                 / PAGE_SIZE + 1) + MAX_LNUM * i;
2127                 pb->lsize[i] = 0;
2128                 pb->lnum[i] = 0;
2129 #endif
2130         }
2131         pb->rawbuf=NULL;
2132         pb->grabbing=0;
2133
2134         /* enable interrupts */
2135         out_le32(&pb->planb_base->intr_stat, PLANB_CLR_IRQ);
2136         pb->intr_mask = PLANB_FRM_IRQ;
2137         enable_irq(pb->irq);
2138
2139         if(video_register_device(&pb->video_dev, VFL_TYPE_GRABBER, video_nr)<0)
2140                 return -1;
2141
2142         return 0;
2143 }
2144
2145 /*
2146  *      Scan for a PlanB controller, request the irq and map the io memory 
2147  */
2148
2149 static int find_planb(void)
2150 {
2151         struct planb            *pb;
2152         struct device_node      *planb_devices;
2153         unsigned char           dev_fn, confreg, bus;
2154         unsigned int            old_base, new_base;
2155         unsigned int            irq;
2156         struct pci_dev          *pdev;
2157         int rc;
2158
2159         if (_machine != _MACH_Pmac)
2160                 return 0;
2161
2162         planb_devices = find_devices("planb");
2163         if (planb_devices == 0) {
2164                 planb_num=0;
2165                 printk(KERN_WARNING "PlanB: no device found!\n");
2166                 return planb_num;
2167         }
2168
2169         if (planb_devices->next != NULL)
2170                 printk(KERN_ERR "Warning: only using first PlanB device!\n");
2171         pb = &planbs[0];
2172         planb_num = 1;
2173
2174         if (planb_devices->n_addrs != 1) {
2175                 printk (KERN_WARNING "PlanB: expecting 1 address for planb "
2176                         "(got %d)", planb_devices->n_addrs);
2177                 return 0;
2178         }
2179
2180         if (planb_devices->n_intrs == 0) {
2181                 printk(KERN_WARNING "PlanB: no intrs for device %s\n",
2182                        planb_devices->full_name);
2183                 return 0;
2184         } else {
2185                 irq = planb_devices->intrs[0].line;
2186         }
2187
2188         /* Initialize PlanB's PCI registers */
2189
2190         /* There is a bug with the way OF assigns addresses
2191            to the devices behind the chaos bridge.
2192            control needs only 0x1000 of space, but decodes only
2193            the upper 16 bits. It therefore occupies a full 64K.
2194            OF assigns the planb controller memory within this space;
2195            so we need to change that here in order to access planb. */
2196
2197         /* We remap to 0xf1000000 in hope that nobody uses it ! */
2198
2199         bus = (planb_devices->addrs[0].space >> 16) & 0xff;
2200         dev_fn = (planb_devices->addrs[0].space >> 8) & 0xff;
2201         confreg = planb_devices->addrs[0].space & 0xff;
2202         old_base = planb_devices->addrs[0].address;
2203         new_base = 0xf1000000;
2204
2205         DEBUG("PlanB: Found on bus %d, dev %d, func %d, "
2206                 "membase 0x%x (base reg. 0x%x)\n",
2207                 bus, PCI_SLOT(dev_fn), PCI_FUNC(dev_fn), old_base, confreg);
2208
2209         pdev = pci_find_slot (bus, dev_fn);
2210         if (!pdev) {
2211                 printk(KERN_ERR "planb: cannot find slot\n");
2212                 goto err_out;
2213         }
2214
2215         /* Enable response in memory space, bus mastering,
2216            use memory write and invalidate */
2217         rc = pci_enable_device(pdev);
2218         if (rc) {
2219                 printk(KERN_ERR "planb: cannot enable PCI device %s\n",
2220                        pci_name(pdev));
2221                 goto err_out;
2222         }
2223         rc = pci_set_mwi(pdev);
2224         if (rc) {
2225                 printk(KERN_ERR "planb: cannot enable MWI on PCI device %s\n",
2226                        pci_name(pdev));
2227                 goto err_out_disable;
2228         }
2229         pci_set_master(pdev);
2230
2231         /* Set the new base address */
2232         pci_write_config_dword (pdev, confreg, new_base);
2233
2234         planb_regs = (volatile struct planb_registers *)
2235                                                 ioremap (new_base, 0x400);
2236         pb->planb_base = planb_regs;
2237         pb->planb_base_phys = (struct planb_registers *)new_base;
2238         pb->irq = irq;
2239         
2240         return planb_num;
2241
2242 err_out_disable:
2243         pci_disable_device(pdev);
2244 err_out:
2245         /* FIXME handle error */   /* comment moved from pci_find_slot, above */
2246         return 0;
2247 }
2248
2249 static void release_planb(void)
2250 {
2251         int i;
2252         struct planb *pb;
2253
2254         for (i=0;i<planb_num; i++) 
2255         {
2256                 pb=&planbs[i];
2257
2258                 /* stop and flash DMAs unconditionally */
2259                 planb_dbdma_stop(&pb->planb_base->ch2);
2260                 planb_dbdma_stop(&pb->planb_base->ch1);
2261
2262                 /* clear and free interrupts */
2263                 pb->intr_mask = PLANB_CLR_IRQ;
2264                 out_le32 (&pb->planb_base->intr_stat, PLANB_CLR_IRQ);
2265                 free_irq(pb->irq, pb);
2266
2267                 /* make sure all allocated memory are freed */
2268                 planb_prepare_close(pb);
2269
2270                 printk(KERN_INFO "PlanB: unregistering with v4l\n");
2271                 video_unregister_device(&pb->video_dev);
2272
2273                 /* note that iounmap() does nothing on the PPC right now */
2274                 iounmap ((void *)pb->planb_base);
2275         }
2276 }
2277
2278 static int __init init_planbs(void)
2279 {
2280         int i;
2281   
2282         if (find_planb()<=0)
2283                 return -EIO;
2284
2285         for (i=0; i<planb_num; i++) {
2286                 if (init_planb(&planbs[i])<0) {
2287                         printk(KERN_ERR "PlanB: error registering device %d"
2288                                                         " with v4l\n", i);
2289                         release_planb();
2290                         return -EIO;
2291                 } 
2292                 printk(KERN_INFO "PlanB: registered device %d with v4l\n", i);
2293         }  
2294         return 0;
2295 }
2296
2297 static void __exit exit_planbs(void)
2298 {
2299         release_planb();
2300 }
2301
2302 module_init(init_planbs);
2303 module_exit(exit_planbs);