ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-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 <asm/uaccess.h>
44 #include <asm/io.h>
45 #include <asm/prom.h>
46 #include <asm/dbdma.h>
47 #include <asm/pgtable.h>
48 #include <asm/page.h>
49 #include <asm/irq.h>
50 #include <asm/semaphore.h>
51
52 #include "planb.h"
53 #include "saa7196.h"
54
55 /* Would you mind for some ugly debugging? */
56 #if 0
57 #define DEBUG(x...) printk(KERN_DEBUG ## x) /* Debug driver */
58 #else
59 #define DEBUG(x...)             /* Don't debug driver */
60 #endif
61
62 #if 0
63 #define IDEBUG(x...) printk(KERN_DEBUG ## x) /* Debug interrupt part */
64 #else
65 #define IDEBUG(x...)            /* Don't debug interrupt part */
66 #endif
67
68 /* Ever seen a Mac with more than 1 of these? */
69 #define PLANB_MAX 1
70
71 static int planb_num;
72 static struct planb planbs[PLANB_MAX];
73 static volatile struct planb_registers *planb_regs;
74
75 static int def_norm = PLANB_DEF_NORM;   /* default norm */
76 static int video_nr = -1;
77
78 MODULE_PARM(def_norm, "i");
79 MODULE_PARM_DESC(def_norm, "Default startup norm (0=PAL, 1=NTSC, 2=SECAM)");
80 MODULE_PARM(video_nr,"i");
81 MODULE_LICENSE("GPL");
82
83
84 /* ------------------ PlanB Exported Functions ------------------ */
85 static long planb_write(struct video_device *, const char *, unsigned long, int);
86 static long planb_read(struct video_device *, char *, unsigned long, int);
87 static int planb_open(struct video_device *, int);
88 static void planb_close(struct video_device *);
89 static int planb_ioctl(struct video_device *, unsigned int, void *);
90 static int planb_init_done(struct video_device *);
91 static int planb_mmap(struct video_device *, const char *, unsigned long);
92 static void planb_irq(int, void *, struct pt_regs *);
93 static void release_planb(void);
94 int init_planbs(struct video_init *);
95
96 /* ------------------ PlanB Internal Functions ------------------ */
97 static int planb_prepare_open(struct planb *);
98 static void planb_prepare_close(struct planb *);
99 static void saa_write_reg(unsigned char, unsigned char);
100 static unsigned char saa_status(int, struct planb *);
101 static void saa_set(unsigned char, unsigned char, struct planb *);
102 static void saa_init_regs(struct planb *);
103 static int grabbuf_alloc(struct planb *);
104 static int vgrab(struct planb *, struct video_mmap *);
105 static void add_clip(struct planb *, struct video_clip *);
106 static void fill_cmd_buff(struct planb *);
107 static void cmd_buff(struct planb *);
108 static volatile struct dbdma_cmd *setup_grab_cmd(int, struct planb *);
109 static void overlay_start(struct planb *);
110 static void overlay_stop(struct planb *);
111 static inline void tab_cmd_dbdma(volatile struct dbdma_cmd *, unsigned short,
112         unsigned int);
113 static inline void tab_cmd_store(volatile struct dbdma_cmd *, unsigned int,
114         unsigned int);
115 static inline void tab_cmd_gen(volatile struct dbdma_cmd *, unsigned short,
116         unsigned short, unsigned int, unsigned int);
117 static int init_planb(struct planb *);
118 static int find_planb(void);
119 static void planb_pre_capture(int, int, struct planb *);
120 static volatile struct dbdma_cmd *cmd_geo_setup(volatile struct dbdma_cmd *,
121                                         int, int, int, int, int, struct planb *);
122 static inline void planb_dbdma_stop(volatile struct dbdma_regs *);
123 static unsigned int saa_geo_setup(int, int, int, int, struct planb *);
124 static inline int overlay_is_active(struct planb *);
125
126 /*******************************/
127 /* Memory management functions */
128 /*******************************/
129
130 static int grabbuf_alloc(struct planb *pb)
131 {
132         int i, npage;
133
134         npage = MAX_GBUFFERS * ((PLANB_MAX_FBUF / PAGE_SIZE + 1)
135 #ifndef PLANB_GSCANLINE
136                 + MAX_LNUM
137 #endif /* PLANB_GSCANLINE */
138                 );
139         if ((pb->rawbuf = (unsigned char**) kmalloc (npage
140                                 * sizeof(unsigned long), GFP_KERNEL)) == 0)
141                 return -ENOMEM;
142         for (i = 0; i < npage; i++) {
143                 pb->rawbuf[i] = (unsigned char *)__get_free_pages(GFP_KERNEL
144                                                                 |GFP_DMA, 0);
145                 if (!pb->rawbuf[i])
146                         break;
147                 SetPageReserved(virt_to_page(pb->rawbuf[i]));
148         }
149         if (i-- < npage) {
150                 printk(KERN_DEBUG "PlanB: init_grab: grab buffer not allocated\n");
151                 for (; i > 0; i--) {
152                         ClearPageReserved(virt_to_page(pb->rawbuf[i]));
153                         free_pages((unsigned long)pb->rawbuf[i], 0);
154                 }
155                 kfree(pb->rawbuf);
156                 return -ENOBUFS;
157         }
158         pb->rawbuf_size = npage;
159         return 0;
160 }
161
162 /*****************************/
163 /* Hardware access functions */
164 /*****************************/
165
166 static void saa_write_reg(unsigned char addr, unsigned char val)
167 {
168         planb_regs->saa_addr = addr; eieio();
169         planb_regs->saa_regval = val; eieio();
170         return;
171 }
172
173 /* return  status byte 0 or 1: */
174 static unsigned char saa_status(int byte, struct planb *pb)
175 {
176         saa_regs[pb->win.norm][SAA7196_STDC] =
177                 (saa_regs[pb->win.norm][SAA7196_STDC] & ~2) | ((byte & 1) << 1);
178         saa_write_reg (SAA7196_STDC, saa_regs[pb->win.norm][SAA7196_STDC]);
179
180         /* Let's wait 30msec for this one */
181         current->state = TASK_INTERRUPTIBLE;
182         schedule_timeout(30 * HZ / 1000);
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         down(&pb->lock);
333 }
334
335 static inline void planb_unlock(struct planb *pb)
336 {
337         up(&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 void overlay_start(struct planb *pb)
426 {
427
428         DEBUG("PlanB: overlay_start()\n");
429
430         if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) {
431
432                 DEBUG("PlanB: presumably, grabbing is in progress...\n");
433
434                 planb_dbdma_stop(&pb->planb_base->ch2);
435                 out_le32 (&pb->planb_base->ch2.cmdptr,
436                                                 virt_to_bus(pb->ch2_cmd));
437                 planb_dbdma_restart(&pb->planb_base->ch2);
438                 st_le16 (&pb->ch1_cmd->command, DBDMA_NOP);
439                 tab_cmd_dbdma(pb->last_cmd[pb->last_fr],
440                                         DBDMA_NOP | BR_ALWAYS,
441                                         virt_to_bus(pb->ch1_cmd));
442                 eieio();
443                 pb->prev_last_fr = pb->last_fr;
444                 pb->last_fr = -2;
445                 if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) {
446                         IDEBUG("PlanB: became inactive "
447                                 "in the mean time... reactivating\n");
448                         planb_dbdma_stop(&pb->planb_base->ch1);
449                         out_le32 (&pb->planb_base->ch1.cmdptr,
450                                                 virt_to_bus(pb->ch1_cmd));
451                         planb_dbdma_restart(&pb->planb_base->ch1);
452                 }
453         } else {
454
455                 DEBUG("PlanB: currently idle, so can do whatever\n");
456
457                 planb_dbdma_stop(&pb->planb_base->ch2);
458                 planb_dbdma_stop(&pb->planb_base->ch1);
459                 st_le32 (&pb->planb_base->ch2.cmdptr,
460                                                 virt_to_bus(pb->ch2_cmd));
461                 st_le32 (&pb->planb_base->ch1.cmdptr,
462                                                 virt_to_bus(pb->ch1_cmd));
463                 out_le16 (&pb->ch1_cmd->command, DBDMA_NOP);
464                 planb_dbdma_restart(&pb->planb_base->ch2);
465                 planb_dbdma_restart(&pb->planb_base->ch1);
466                 pb->last_fr = -1;
467         }
468         return;
469 }
470
471 static void overlay_stop(struct planb *pb)
472 {
473         DEBUG("PlanB: overlay_stop()\n");
474
475         if(pb->last_fr == -1) {
476
477                 DEBUG("PlanB: no grabbing, it seems...\n");
478
479                 planb_dbdma_stop(&pb->planb_base->ch2);
480                 planb_dbdma_stop(&pb->planb_base->ch1);
481                 pb->last_fr = -999;
482         } else if(pb->last_fr == -2) {
483                 unsigned int cmd_dep;
484                 tab_cmd_dbdma(pb->cap_cmd[pb->prev_last_fr], DBDMA_STOP, 0);
485                 eieio();
486                 cmd_dep = (unsigned int)in_le32(&pb->overlay_last1->cmd_dep);
487                 if(overlay_is_active(pb)) {
488
489                         DEBUG("PlanB: overlay is currently active\n");
490
491                         planb_dbdma_stop(&pb->planb_base->ch2);
492                         planb_dbdma_stop(&pb->planb_base->ch1);
493                         if(cmd_dep != pb->ch1_cmd_phys) {
494                                 out_le32(&pb->planb_base->ch1.cmdptr,
495                                                 virt_to_bus(pb->overlay_last1));
496                                 planb_dbdma_restart(&pb->planb_base->ch1);
497                         }
498                 }
499                 pb->last_fr = pb->prev_last_fr;
500                 pb->prev_last_fr = -999;
501         }
502         return;
503 }
504
505 static void suspend_overlay(struct planb *pb)
506 {
507         int fr = -1;
508         struct dbdma_cmd last;
509
510         DEBUG("PlanB: suspend_overlay: %d\n", pb->suspend);
511
512         if(pb->suspend++)
513                 return;
514         if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) {
515                 if(pb->last_fr == -2) {
516                         fr = pb->prev_last_fr;
517                         memcpy(&last, (void*)pb->last_cmd[fr], sizeof(last));
518                         tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0);
519                 }
520                 if(overlay_is_active(pb)) {
521                         planb_dbdma_stop(&pb->planb_base->ch2);
522                         planb_dbdma_stop(&pb->planb_base->ch1);
523                         pb->suspended.overlay = 1;
524                         pb->suspended.frame = fr;
525                         memcpy(&pb->suspended.cmd, &last, sizeof(last));
526                         return;
527                 }
528         }
529         pb->suspended.overlay = 0;
530         pb->suspended.frame = fr;
531         memcpy(&pb->suspended.cmd, &last, sizeof(last));
532         return;
533 }
534
535 static void resume_overlay(struct planb *pb)
536 {
537
538         DEBUG("PlanB: resume_overlay: %d\n", pb->suspend);
539
540         if(pb->suspend > 1)
541                 return;
542         if(pb->suspended.frame != -1) {
543                 memcpy((void*)pb->last_cmd[pb->suspended.frame],
544                                 &pb->suspended.cmd, sizeof(pb->suspended.cmd));
545         }
546         if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) {
547                 goto finish;
548         }
549         if(pb->suspended.overlay) {
550
551                 DEBUG("PlanB: overlay being resumed\n");
552
553                 st_le16 (&pb->ch1_cmd->command, DBDMA_NOP);
554                 st_le16 (&pb->ch2_cmd->command, DBDMA_NOP);
555                 /* Set command buffer addresses */
556                 st_le32(&pb->planb_base->ch1.cmdptr,
557                                         virt_to_bus(pb->overlay_last1));
558                 out_le32(&pb->planb_base->ch2.cmdptr,
559                                         virt_to_bus(pb->overlay_last2));
560                 /* Start the DMA controller */
561                 out_le32 (&pb->planb_base->ch2.control,
562                                 PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE));
563                 out_le32 (&pb->planb_base->ch1.control,
564                                 PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE));
565         } else if(pb->suspended.frame != -1) {
566                 out_le32(&pb->planb_base->ch1.cmdptr,
567                                 virt_to_bus(pb->last_cmd[pb->suspended.frame]));
568                 out_le32 (&pb->planb_base->ch1.control,
569                                 PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE));
570         }
571
572 finish:
573         pb->suspend--;
574         wake_up_interruptible(&pb->suspendq);
575 }
576
577 static void add_clip(struct planb *pb, struct video_clip *clip) 
578 {
579         volatile unsigned char  *base;
580         int     xc = clip->x, yc = clip->y;
581         int     wc = clip->width, hc = clip->height;
582         int     ww = pb->win.width, hw = pb->win.height;
583         int     x, y, xtmp1, xtmp2;
584
585         DEBUG("PlanB: clip %dx%d+%d+%d\n", wc, hc, xc, yc);
586
587         if(xc < 0) {
588                 wc += xc;
589                 xc = 0;
590         }
591         if(yc < 0) {
592                 hc += yc;
593                 yc = 0;
594         }
595         if(xc + wc > ww)
596                 wc = ww - xc;
597         if(wc <= 0) /* Nothing to do */
598                 return;
599         if(yc + hc > hw)
600                 hc = hw - yc;
601
602         for (y = yc; y < yc+hc; y++) {
603                 xtmp1=xc>>3;
604                 xtmp2=(xc+wc)>>3;
605                 base = pb->mask + y*96;
606                 if(xc != 0 || wc >= 8)
607                         *(base + xtmp1) &= (unsigned char)(0x00ff &
608                                 (0xff00 >> (xc&7)));
609                 for (x = xtmp1 + 1; x < xtmp2; x++) {
610                         *(base + x) = 0;
611                 }
612                 if(xc < (ww & ~0x7))
613                         *(base + xtmp2) &= (unsigned char)(0x00ff >>
614                                 ((xc+wc) & 7));
615         }
616
617         return;
618 }
619
620 static void fill_cmd_buff(struct planb *pb)
621 {
622         int restore = 0;
623         volatile struct dbdma_cmd last;
624
625         DEBUG("PlanB: fill_cmd_buff()\n");
626
627         if(pb->overlay_last1 != pb->ch1_cmd) {
628                 restore = 1;
629                 last = *(pb->overlay_last1);
630         }
631         memset ((void *) pb->ch1_cmd, 0, 2 * pb->tab_size
632                                         * sizeof(struct dbdma_cmd));
633         cmd_buff (pb);
634         if(restore)
635                 *(pb->overlay_last1) = last;
636         if(pb->suspended.overlay) {
637                 unsigned long jump_addr = in_le32(&pb->overlay_last1->cmd_dep);
638                 if(jump_addr != pb->ch1_cmd_phys) {
639                         int i;
640
641                         DEBUG("PlanB: adjusting ch1's jump address\n");
642
643                         for(i = 0; i < MAX_GBUFFERS; i++) {
644                                 if(pb->need_pre_capture[i]) {
645                                     if(jump_addr == virt_to_bus(pb->pre_cmd[i]))
646                                         goto found;
647                                 } else {
648                                     if(jump_addr == virt_to_bus(pb->cap_cmd[i]))
649                                         goto found;
650                                 }
651                         }
652
653                         DEBUG("PlanB: not found...\n");
654
655                         goto out;
656 found:
657                         if(pb->need_pre_capture[i])
658                                 out_le32(&pb->pre_cmd[i]->phy_addr,
659                                                 virt_to_bus(pb->overlay_last1));
660                         else
661                                 out_le32(&pb->cap_cmd[i]->phy_addr,
662                                                 virt_to_bus(pb->overlay_last1));
663                 }
664         }
665 out:
666         pb->cmd_buff_inited = 1;
667
668         return;
669 }
670
671 static void cmd_buff(struct planb *pb)
672 {
673         int             i, bpp, count, nlines, stepsize, interlace;
674         unsigned long   base, jump, addr_com, addr_dep;
675         volatile struct dbdma_cmd *c1 = pb->ch1_cmd;
676         volatile struct dbdma_cmd *c2 = pb->ch2_cmd;
677
678         interlace = pb->win.interlace;
679         bpp = pb->win.bpp;
680         count = (bpp * ((pb->win.x + pb->win.width > pb->win.swidth) ?
681                 (pb->win.swidth - pb->win.x) : pb->win.width));
682         nlines = ((pb->win.y + pb->win.height > pb->win.sheight) ?
683                 (pb->win.sheight - pb->win.y) : pb->win.height);
684
685         /* Do video in: */
686
687         /* Preamble commands: */
688         addr_com = virt_to_bus(c1);
689         addr_dep = virt_to_bus(&c1->cmd_dep);
690         tab_cmd_dbdma(c1++, DBDMA_NOP, 0);
691         jump = virt_to_bus(c1+16); /* 14 by cmd_geo_setup() and 2 for padding */
692         if((c1 = cmd_geo_setup(c1, pb->win.width, pb->win.height, interlace,
693                                         bpp, 1, pb)) == NULL) {
694                 printk(KERN_WARNING "PlanB: encountered serious problems\n");
695                 tab_cmd_dbdma(pb->ch1_cmd + 1, DBDMA_STOP, 0);
696                 tab_cmd_dbdma(pb->ch2_cmd + 1, DBDMA_STOP, 0);
697                 return;
698         }
699         tab_cmd_store(c1++, addr_com, (unsigned)(DBDMA_NOP | BR_ALWAYS) << 16);
700         tab_cmd_store(c1++, addr_dep, jump);
701         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel),
702                                                         PLANB_SET(FIELD_SYNC));
703                 /* (1) wait for field sync to be set */
704         tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
705         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
706                                                         PLANB_SET(ODD_FIELD));
707                 /* wait for field sync to be cleared */
708         tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
709                 /* if not odd field, wait until field sync is set again */
710         tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++;
711                 /* assert ch_sync to ch2 */
712         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch2.control),
713                                                         PLANB_SET(CH_SYNC));
714         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
715                                                         PLANB_SET(DMA_ABORT));
716
717         base = (pb->frame_buffer_phys + pb->offset + pb->win.y * (pb->win.bpl
718                                         + pb->win.pad) + pb->win.x * bpp);
719
720         if (interlace) {
721                 stepsize = 2;
722                 jump = virt_to_bus(c1 + (nlines + 1) / 2);
723         } else {
724                 stepsize = 1;
725                 jump = virt_to_bus(c1 + nlines);
726         }
727
728         /* even field data: */
729         for (i=0; i < nlines; i += stepsize, c1++)
730                 tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET,
731                         count, base + i * (pb->win.bpl + pb->win.pad), jump);
732
733         /* For non-interlaced, we use even fields only */
734         if (!interlace)
735                 goto cmd_tab_data_end;
736
737         /* Resync to odd field */
738                 /* (2) wait for field sync to be set */
739         tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
740         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
741                                                         PLANB_SET(ODD_FIELD));
742                 /* wait for field sync to be cleared */
743         tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
744                 /* if not odd field, wait until field sync is set again */
745         tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++;
746                 /* assert ch_sync to ch2 */
747         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch2.control),
748                                                         PLANB_SET(CH_SYNC));
749         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
750                                                         PLANB_SET(DMA_ABORT));
751         
752         /* odd field data: */
753         jump = virt_to_bus(c1 + nlines / 2);
754         for (i=1; i < nlines; i += stepsize, c1++)
755                 tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count,
756                         base + i * (pb->win.bpl + pb->win.pad), jump);
757
758         /* And jump back to the start */
759 cmd_tab_data_end:
760         pb->overlay_last1 = c1; /* keep a pointer to the last command */
761         tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->ch1_cmd));
762
763         /* Clipmask command buffer */
764
765         /* Preamble commands: */
766         tab_cmd_dbdma(c2++, DBDMA_NOP, 0);
767         tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.wait_sel),
768                                                         PLANB_SET(CH_SYNC));
769                 /* wait until ch1 asserts ch_sync */
770         tab_cmd_dbdma(c2++, DBDMA_NOP | WAIT_IFCLR, 0);
771                 /* clear ch_sync asserted by ch1 */
772         tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.control),
773                                                         PLANB_CLR(CH_SYNC));
774         tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.wait_sel),
775                                                         PLANB_SET(FIELD_SYNC));
776         tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel),
777                                                         PLANB_SET(ODD_FIELD));
778
779         /* jump to end of even field if appropriate */
780         /* this points to (interlace)? pos. C: pos. B */
781         jump = (interlace) ? virt_to_bus(c2 + (nlines + 1) / 2 + 2):
782                                                 virt_to_bus(c2 + nlines + 2);
783                 /* if odd field, skip over to odd field clipmasking */
784         tab_cmd_dbdma(c2++, DBDMA_NOP | BR_IFSET, jump);
785
786         /* even field mask: */
787         tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel),
788                                                         PLANB_SET(DMA_ABORT));
789         /* this points to pos. B */
790         jump = (interlace) ? virt_to_bus(c2 + nlines + 1):
791                                                 virt_to_bus(c2 + nlines);
792         base = virt_to_bus(pb->mask);
793         for (i=0; i < nlines; i += stepsize, c2++)
794                 tab_cmd_gen(c2, OUTPUT_MORE | KEY_STREAM0 | BR_IFSET, 96,
795                         base + i * 96, jump);
796
797         /* For non-interlaced, we use only even fields */
798         if(!interlace)
799                 goto cmd_tab_mask_end;
800
801         /* odd field mask: */
802 /* C */ tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel),
803                                                         PLANB_SET(DMA_ABORT));
804         /* this points to pos. B */
805         jump = virt_to_bus(c2 + nlines / 2);
806         base = virt_to_bus(pb->mask);
807         for (i=1; i < nlines; i += 2, c2++)     /* abort if set */
808                 tab_cmd_gen(c2, OUTPUT_MORE | KEY_STREAM0 | BR_IFSET, 96,
809                         base + i * 96, jump);
810
811         /* Inform channel 1 and jump back to start */
812 cmd_tab_mask_end:
813         /* ok, I just realized this is kind of flawed. */
814         /* this part is reached only after odd field clipmasking. */
815         /* wanna clean up? */
816                 /* wait for field sync to be set */
817                 /* corresponds to fsync (1) of ch1 */
818 /* B */ tab_cmd_dbdma(c2++, DBDMA_NOP | WAIT_IFCLR, 0);
819                 /* restart ch1, meant to clear any dead bit or something */
820         tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch1.control),
821                                                         PLANB_CLR(RUN));
822         tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch1.control),
823                                                         PLANB_SET(RUN));
824         pb->overlay_last2 = c2; /* keep a pointer to the last command */
825                 /* start over even field clipmasking */
826         tab_cmd_dbdma(c2, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->ch2_cmd));
827
828         eieio();
829         return;
830 }
831
832 /*********************************/
833 /* grabdisplay support functions */
834 /*********************************/
835
836 static int palette2fmt[] = {
837        0,
838        PLANB_GRAY,
839        0,
840        0,
841        0,
842        PLANB_COLOUR32,
843        PLANB_COLOUR15,
844        0,
845        0,
846        0,
847        0,
848        0,
849        0,
850        0,
851        0,
852 };
853
854 #define PLANB_PALETTE_MAX 15
855
856 static inline int overlay_is_active(struct planb *pb)
857 {
858         unsigned int size = pb->tab_size * sizeof(struct dbdma_cmd);
859         unsigned int caddr = (unsigned)in_le32(&pb->planb_base->ch1.cmdptr);
860
861         return (in_le32(&pb->overlay_last1->cmd_dep) == pb->ch1_cmd_phys)
862                         && (caddr < (pb->ch1_cmd_phys + size))
863                         && (caddr >= (unsigned)pb->ch1_cmd_phys);
864 }
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
1387         MOD_INC_USE_COUNT;
1388         return 0;   
1389 }
1390
1391 static void planb_close(struct video_device *dev)
1392 {
1393         struct planb *pb = (struct planb *)dev;
1394
1395         if(pb->user < 1) /* ??? */
1396                 return;
1397         planb_lock(pb);
1398         if (pb->user == 1) {
1399                 if (pb->overlay) {
1400                         planb_dbdma_stop(&pb->planb_base->ch2);
1401                         planb_dbdma_stop(&pb->planb_base->ch1);
1402                         pb->overlay = 0;
1403                 }
1404                 planb_prepare_close(pb);
1405         }
1406         pb->user--;
1407         planb_unlock(pb);
1408
1409         DEBUG("PlanB: device closed\n");
1410
1411         MOD_DEC_USE_COUNT;  
1412 }
1413
1414 static long planb_read(struct video_device *v, char *buf, unsigned long count,
1415                                 int nonblock)
1416 {
1417         DEBUG("planb: read request\n");
1418         return -EINVAL;
1419 }
1420
1421 static long planb_write(struct video_device *v, const char *buf,
1422                                 unsigned long count, int nonblock)
1423 {
1424         DEBUG("planb: write request\n");
1425         return -EINVAL;
1426 }
1427
1428 static int planb_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
1429 {
1430         struct planb *pb=(struct planb *)dev;
1431         
1432         switch (cmd)
1433         {       
1434                 case VIDIOCGCAP:
1435                 {
1436                         struct video_capability b;
1437
1438                         DEBUG("PlanB: IOCTL VIDIOCGCAP\n");
1439
1440                         strcpy (b.name, pb->video_dev.name);
1441                         b.type = VID_TYPE_OVERLAY | VID_TYPE_CLIPPING |
1442                                  VID_TYPE_FRAMERAM | VID_TYPE_SCALES |
1443                                  VID_TYPE_CAPTURE;
1444                         b.channels = 2; /* composite & svhs */
1445                         b.audios = 0;
1446                         b.maxwidth = PLANB_MAXPIXELS;
1447                         b.maxheight = PLANB_MAXLINES;
1448                         b.minwidth = 32; /* wild guess */
1449                         b.minheight = 32;
1450                         if (copy_to_user(arg,&b,sizeof(b)))
1451                                 return -EFAULT;
1452                         return 0;
1453                 }
1454                 case VIDIOCSFBUF:
1455                 {
1456                         struct video_buffer v;
1457                         unsigned short bpp;
1458                         unsigned int fmt;
1459
1460                         DEBUG("PlanB: IOCTL VIDIOCSFBUF\n");
1461
1462                         if (!capable(CAP_SYS_ADMIN)
1463                         || !capable(CAP_SYS_RAWIO))
1464                                 return -EPERM;
1465                         if (copy_from_user(&v, arg,sizeof(v)))
1466                                 return -EFAULT;
1467                         planb_lock(pb);
1468                         switch(v.depth) {
1469                         case 8:
1470                                 bpp = 1;
1471                                 fmt = PLANB_GRAY;
1472                                 break;
1473                         case 15:
1474                         case 16:
1475                                 bpp = 2;
1476                                 fmt = PLANB_COLOUR15;
1477                                 break;
1478                         case 24:
1479                         case 32:
1480                                 bpp = 4;
1481                                 fmt = PLANB_COLOUR32;
1482                                 break;
1483                         default:
1484                                 planb_unlock(pb);
1485                                 return -EINVAL;
1486                         }
1487                         if (bpp * v.width > v.bytesperline) {
1488                                 planb_unlock(pb);
1489                                 return -EINVAL;
1490                         }
1491                         pb->win.bpp = bpp;
1492                         pb->win.color_fmt = fmt;
1493                         pb->frame_buffer_phys = (unsigned long) v.base;
1494                         pb->win.sheight = v.height;
1495                         pb->win.swidth = v.width;
1496                         pb->picture.depth = pb->win.depth = v.depth;
1497                         pb->win.bpl = pb->win.bpp * pb->win.swidth;
1498                         pb->win.pad = v.bytesperline - pb->win.bpl;
1499
1500                         DEBUG("PlanB: Display at %p is %d by %d, bytedepth %d,"
1501                                 " bpl %d (+ %d)\n", v.base, v.width,v.height,
1502                                 pb->win.bpp, pb->win.bpl, pb->win.pad);
1503
1504                         pb->cmd_buff_inited = 0;
1505                         if(pb->overlay) {
1506                                 suspend_overlay(pb);
1507                                 fill_cmd_buff(pb);
1508                                 resume_overlay(pb);
1509                         }
1510                         planb_unlock(pb);
1511                         return 0;               
1512                 }
1513                 case VIDIOCGFBUF:
1514                 {
1515                         struct video_buffer v;
1516
1517                         DEBUG("PlanB: IOCTL VIDIOCGFBUF\n");
1518
1519                         v.base = (void *)pb->frame_buffer_phys;
1520                         v.height = pb->win.sheight;
1521                         v.width = pb->win.swidth;
1522                         v.depth = pb->win.depth;
1523                         v.bytesperline = pb->win.bpl + pb->win.pad;
1524                         if (copy_to_user(arg, &v, sizeof(v)))
1525                                 return -EFAULT;
1526                         return 0;
1527                 }
1528                 case VIDIOCCAPTURE:
1529                 {
1530                         int i;
1531
1532                         if(copy_from_user(&i, arg, sizeof(i)))
1533                                 return -EFAULT;
1534                         if(i==0) {
1535                                 DEBUG("PlanB: IOCTL VIDIOCCAPTURE Stop\n");
1536
1537                                 if (!(pb->overlay))
1538                                         return 0;
1539                                 planb_lock(pb);
1540                                 pb->overlay = 0;
1541                                 overlay_stop(pb);
1542                                 planb_unlock(pb);
1543                         } else {
1544                                 DEBUG("PlanB: IOCTL VIDIOCCAPTURE Start\n");
1545
1546                                 if (pb->frame_buffer_phys == 0 ||
1547                                           pb->win.width == 0 ||
1548                                           pb->win.height == 0)
1549                                         return -EINVAL;
1550                                 if (pb->overlay)
1551                                         return 0;
1552                                 planb_lock(pb);
1553                                 pb->overlay = 1;
1554                                 if(!(pb->cmd_buff_inited))
1555                                         fill_cmd_buff(pb);
1556                                 overlay_start(pb);
1557                                 planb_unlock(pb);
1558                         }
1559                         return 0;
1560                 }
1561                 case VIDIOCGCHAN:
1562                 {
1563                         struct video_channel v;
1564
1565                         DEBUG("PlanB: IOCTL VIDIOCGCHAN\n");
1566
1567                         if(copy_from_user(&v, arg,sizeof(v)))
1568                                 return -EFAULT;
1569                         v.flags = 0;
1570                         v.tuners = 0;
1571                         v.type = VIDEO_TYPE_CAMERA;
1572                         v.norm = pb->win.norm;
1573                         switch(v.channel)
1574                         {
1575                         case 0:
1576                                 strcpy(v.name,"Composite");
1577                                 break;
1578                         case 1:
1579                                 strcpy(v.name,"SVHS");
1580                                 break;
1581                         default:
1582                                 return -EINVAL;
1583                                 break;
1584                         }
1585                         if(copy_to_user(arg,&v,sizeof(v)))
1586                                 return -EFAULT;
1587
1588                         return 0;
1589                 }
1590                 case VIDIOCSCHAN:
1591                 {
1592                         struct video_channel v;
1593
1594                         DEBUG("PlanB: IOCTL VIDIOCSCHAN\n");
1595
1596                         if(copy_from_user(&v, arg, sizeof(v)))
1597                                 return -EFAULT;
1598
1599                         if (v.norm != pb->win.norm) {
1600                                 int i, maxlines;
1601
1602                                 switch (v.norm)
1603                                 {
1604                                 case VIDEO_MODE_PAL:
1605                                 case VIDEO_MODE_SECAM:
1606                                         maxlines = PLANB_MAXLINES;
1607                                         break;
1608                                 case VIDEO_MODE_NTSC:
1609                                         maxlines = PLANB_NTSC_MAXLINES;
1610                                         break;
1611                                 default:
1612                                         return -EINVAL;
1613                                         break;
1614                                 }
1615                                 planb_lock(pb);
1616                                 /* empty the grabbing queue */
1617                                 while(pb->grabbing)
1618                                         interruptible_sleep_on(&pb->capq);
1619                                 pb->maxlines = maxlines;
1620                                 pb->win.norm = v.norm;
1621                                 /* Stop overlay if running */
1622                                 suspend_overlay(pb);
1623                                 for(i = 0; i < MAX_GBUFFERS; i++)
1624                                         pb->gnorm_switch[i] = 1;
1625                                 /* I know it's an overkill, but.... */
1626                                 fill_cmd_buff(pb);
1627                                 /* ok, now init it accordingly */
1628                                 saa_init_regs (pb);
1629                                 /* restart overlay if it was running */
1630                                 resume_overlay(pb);
1631                                 planb_unlock(pb);
1632                         }
1633
1634                         switch(v.channel)
1635                         {
1636                         case 0: /* Composite    */
1637                                 saa_set (SAA7196_IOCC,
1638                                         ((saa_regs[pb->win.norm][SAA7196_IOCC] &
1639                                           ~7) | 3), pb);
1640                                 break;
1641                         case 1: /* SVHS         */
1642                                 saa_set (SAA7196_IOCC,
1643                                         ((saa_regs[pb->win.norm][SAA7196_IOCC] &
1644                                           ~7) | 4), pb);
1645                                 break;
1646                         default:
1647                                 return -EINVAL;
1648                                 break;
1649                         }
1650
1651                         return 0;
1652                 }
1653                 case VIDIOCGPICT:
1654                 {
1655                         struct video_picture vp = pb->picture;
1656
1657                         DEBUG("PlanB: IOCTL VIDIOCGPICT\n");
1658
1659                         switch(pb->win.color_fmt) {
1660                         case PLANB_GRAY:
1661                                 vp.palette = VIDEO_PALETTE_GREY;
1662                         case PLANB_COLOUR15:
1663                                 vp.palette = VIDEO_PALETTE_RGB555;
1664                                 break;
1665                         case PLANB_COLOUR32:
1666                                 vp.palette = VIDEO_PALETTE_RGB32;
1667                                 break;
1668                         default:
1669                                 vp.palette = 0;
1670                                 break;
1671                         }
1672
1673                         if(copy_to_user(arg,&vp,sizeof(vp)))
1674                                 return -EFAULT;
1675                         return 0;
1676                 }
1677                 case VIDIOCSPICT:
1678                 {
1679                         struct video_picture vp;
1680
1681                         DEBUG("PlanB: IOCTL VIDIOCSPICT\n");
1682
1683                         if(copy_from_user(&vp,arg,sizeof(vp)))
1684                                 return -EFAULT;
1685                         pb->picture = vp;
1686                         /* Should we do sanity checks here? */
1687                         saa_set (SAA7196_BRIG, (unsigned char)
1688                             ((pb->picture.brightness) >> 8), pb);
1689                         saa_set (SAA7196_HUEC, (unsigned char)
1690                             ((pb->picture.hue) >> 8) ^ 0x80, pb);
1691                         saa_set (SAA7196_CSAT, (unsigned char)
1692                             ((pb->picture.colour) >> 9), pb);
1693                         saa_set (SAA7196_CONT, (unsigned char)
1694                             ((pb->picture.contrast) >> 9), pb);
1695
1696                         return 0;
1697                 }
1698                 case VIDIOCSWIN:
1699                 {
1700                         struct video_window     vw;
1701                         struct video_clip       clip;
1702                         int                     i;
1703                         
1704                         DEBUG("PlanB: IOCTL VIDIOCSWIN\n");
1705
1706                         if(copy_from_user(&vw,arg,sizeof(vw)))
1707                                 return -EFAULT;
1708
1709                         planb_lock(pb);
1710                         /* Stop overlay if running */
1711                         suspend_overlay(pb);
1712                         pb->win.interlace = (vw.height > pb->maxlines/2)? 1: 0;
1713                         if (pb->win.x != vw.x ||
1714                             pb->win.y != vw.y ||
1715                             pb->win.width != vw.width ||
1716                             pb->win.height != vw.height ||
1717                             !pb->cmd_buff_inited) {
1718                                 pb->win.x = vw.x;
1719                                 pb->win.y = vw.y;
1720                                 pb->win.width = vw.width;
1721                                 pb->win.height = vw.height;
1722                                 fill_cmd_buff(pb);
1723                         }
1724                         /* Reset clip mask */
1725                         memset ((void *) pb->mask, 0xff, (pb->maxlines
1726                                         * ((PLANB_MAXPIXELS + 7) & ~7)) / 8);
1727                         /* Add any clip rects */
1728                         for (i = 0; i < vw.clipcount; i++) {
1729                                 if (copy_from_user(&clip, vw.clips + i,
1730                                                 sizeof(struct video_clip)))
1731                                         return -EFAULT;
1732                                 add_clip(pb, &clip);
1733                         }
1734                         /* restart overlay if it was running */
1735                         resume_overlay(pb);
1736                         planb_unlock(pb);
1737                         return 0;
1738                 }
1739                 case VIDIOCGWIN:
1740                 {
1741                         struct video_window vw;
1742
1743                         DEBUG("PlanB: IOCTL VIDIOCGWIN\n");
1744
1745                         vw.x=pb->win.x;
1746                         vw.y=pb->win.y;
1747                         vw.width=pb->win.width;
1748                         vw.height=pb->win.height;
1749                         vw.chromakey=0;
1750                         vw.flags=0;
1751                         if(pb->win.interlace)
1752                                 vw.flags|=VIDEO_WINDOW_INTERLACE;
1753                         if(copy_to_user(arg,&vw,sizeof(vw)))
1754                                 return -EFAULT;
1755                         return 0;
1756                 }
1757                 case VIDIOCSYNC: {
1758                         int i;
1759
1760                         IDEBUG("PlanB: IOCTL VIDIOCSYNC\n");
1761
1762                         if(copy_from_user((void *)&i,arg,sizeof(int)))
1763                                 return -EFAULT;
1764
1765                         IDEBUG("PlanB: sync to frame %d\n", i);
1766
1767                         if(i > (MAX_GBUFFERS - 1) || i < 0)
1768                                 return -EINVAL;
1769 chk_grab:
1770                         switch (pb->frame_stat[i]) {
1771                         case GBUFFER_UNUSED:
1772                                 return -EINVAL;
1773                         case GBUFFER_GRABBING:
1774                                 IDEBUG("PlanB: waiting for grab"
1775                                                         " done (%d)\n", i);
1776                                 interruptible_sleep_on(&pb->capq);
1777                                 if(signal_pending(current))
1778                                         return -EINTR;
1779                                 goto chk_grab;
1780                         case GBUFFER_DONE:
1781                                 pb->frame_stat[i] = GBUFFER_UNUSED;
1782                                 break;
1783                         }
1784                         return 0;
1785                 }
1786
1787                 case VIDIOCMCAPTURE:
1788                 {
1789                         struct video_mmap vm;
1790                         volatile unsigned int status;
1791
1792                         IDEBUG("PlanB: IOCTL VIDIOCMCAPTURE\n");
1793
1794                         if(copy_from_user((void *) &vm,(void *)arg,sizeof(vm)))
1795                                 return -EFAULT;
1796                         status = pb->frame_stat[vm.frame];
1797                         if (status != GBUFFER_UNUSED)
1798                                 return -EBUSY;
1799
1800                         return vgrab(pb, &vm);
1801                 }
1802                 
1803                 case VIDIOCGMBUF:
1804                 {
1805                         int i;
1806                         struct video_mbuf vm;
1807
1808                         DEBUG("PlanB: IOCTL VIDIOCGMBUF\n");
1809
1810                         memset(&vm, 0 , sizeof(vm));
1811                         vm.size = PLANB_MAX_FBUF * MAX_GBUFFERS;
1812                         vm.frames = MAX_GBUFFERS;
1813                         for(i = 0; i<MAX_GBUFFERS; i++)
1814                                 vm.offsets[i] = PLANB_MAX_FBUF * i;
1815                         if(copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
1816                                 return -EFAULT;
1817                         return 0;
1818                 }
1819                 
1820                 case PLANBIOCGSAAREGS:
1821                 {
1822                         struct planb_saa_regs preg;
1823
1824                         DEBUG("PlanB: IOCTL PLANBIOCGSAAREGS\n");
1825
1826                         if(copy_from_user(&preg, arg, sizeof(preg)))
1827                                 return -EFAULT;
1828                         if(preg.addr >= SAA7196_NUMREGS)
1829                                 return -EINVAL;
1830                         preg.val = saa_regs[pb->win.norm][preg.addr];
1831                         if(copy_to_user((void *)arg, (void *)&preg,
1832                                                                 sizeof(preg)))
1833                                 return -EFAULT;
1834                         return 0;
1835                 }
1836                 
1837                 case PLANBIOCSSAAREGS:
1838                 {
1839                         struct planb_saa_regs preg;
1840
1841                         DEBUG("PlanB: IOCTL PLANBIOCSSAAREGS\n");
1842
1843                         if(copy_from_user(&preg, arg, sizeof(preg)))
1844                                 return -EFAULT;
1845                         if(preg.addr >= SAA7196_NUMREGS)
1846                                 return -EINVAL;
1847                         saa_set (preg.addr, preg.val, pb);
1848                         return 0;
1849                 }
1850                 
1851                 case PLANBIOCGSTAT:
1852                 {
1853                         struct planb_stat_regs pstat;
1854
1855                         DEBUG("PlanB: IOCTL PLANBIOCGSTAT\n");
1856
1857                         pstat.ch1_stat = in_le32(&pb->planb_base->ch1.status);
1858                         pstat.ch2_stat = in_le32(&pb->planb_base->ch2.status);
1859                         pstat.saa_stat0 = saa_status(0, pb);
1860                         pstat.saa_stat1 = saa_status(1, pb);
1861
1862                         if(copy_to_user((void *)arg, (void *)&pstat,
1863                                                         sizeof(pstat)))
1864                                 return -EFAULT;
1865                         return 0;
1866                 }
1867                 
1868                 case PLANBIOCSMODE: {
1869                         int v;
1870
1871                         DEBUG("PlanB: IOCTL PLANBIOCSMODE\n");
1872
1873                         if(copy_from_user(&v, arg, sizeof(v)))
1874                                 return -EFAULT;
1875
1876                         switch(v)
1877                         {
1878                         case PLANB_TV_MODE:
1879                                 saa_set (SAA7196_STDC,
1880                                         (saa_regs[pb->win.norm][SAA7196_STDC] &
1881                                           0x7f), pb);
1882                                 break;
1883                         case PLANB_VTR_MODE:
1884                                 saa_set (SAA7196_STDC,
1885                                         (saa_regs[pb->win.norm][SAA7196_STDC] |
1886                                           0x80), pb);
1887                                 break;
1888                         default:
1889                                 return -EINVAL;
1890                                 break;
1891                         }
1892                         pb->win.mode = v;
1893                         return 0;
1894                 }
1895                 case PLANBIOCGMODE: {
1896                         int v=pb->win.mode;
1897
1898                         DEBUG("PlanB: IOCTL PLANBIOCGMODE\n");
1899
1900                         if(copy_to_user(arg,&v,sizeof(v)))
1901                                 return -EFAULT;
1902                         return 0;
1903                 }
1904 #ifdef PLANB_GSCANLINE
1905                 case PLANBG_GRAB_BPL: {
1906                         int v=pb->gbytes_per_line;
1907
1908                         DEBUG("PlanB: IOCTL PLANBG_GRAB_BPL\n");
1909
1910                         if(copy_to_user(arg,&v,sizeof(v)))
1911                                 return -EFAULT;
1912                         return 0;
1913                 }
1914 #endif /* PLANB_GSCANLINE */
1915                 case PLANB_INTR_DEBUG: {
1916                         int i;
1917
1918                         DEBUG("PlanB: IOCTL PLANB_INTR_DEBUG\n");
1919
1920                         if(copy_from_user(&i, arg, sizeof(i)))
1921                                 return -EFAULT;
1922
1923                         /* avoid hang ups all together */
1924                         for (i = 0; i < MAX_GBUFFERS; i++) {
1925                                 if(pb->frame_stat[i] == GBUFFER_GRABBING) {
1926                                         pb->frame_stat[i] = GBUFFER_DONE;
1927                                 }
1928                         }
1929                         if(pb->grabbing)
1930                                 pb->grabbing--;
1931                         wake_up_interruptible(&pb->capq);
1932                         return 0;
1933                 }
1934                 case PLANB_INV_REGS: {
1935                         int i;
1936                         struct planb_any_regs any;
1937
1938                         DEBUG("PlanB: IOCTL PLANB_INV_REGS\n");
1939
1940                         if(copy_from_user(&any, arg, sizeof(any)))
1941                                 return -EFAULT;
1942                         if(any.offset < 0 || any.offset + any.bytes > 0x400)
1943                                 return -EINVAL;
1944                         if(any.bytes > 128)
1945                                 return -EINVAL;
1946                         for (i = 0; i < any.bytes; i++) {
1947                                 any.data[i] =
1948                                         in_8((unsigned char *)pb->planb_base
1949                                                         + any.offset + i);
1950                         }
1951                         if(copy_to_user(arg,&any,sizeof(any)))
1952                                 return -EFAULT;
1953                         return 0;
1954                 }
1955                 default:
1956                 {
1957                         DEBUG("PlanB: Unimplemented IOCTL\n");
1958                         return -ENOIOCTLCMD;
1959                 }
1960         /* Some IOCTLs are currently unsupported on PlanB */
1961                 case VIDIOCGTUNER: {
1962                 DEBUG("PlanB: IOCTL VIDIOCGTUNER\n");
1963                         goto unimplemented; }
1964                 case VIDIOCSTUNER: {
1965                 DEBUG("PlanB: IOCTL VIDIOCSTUNER\n");
1966                         goto unimplemented; }
1967                 case VIDIOCSFREQ: {
1968                 DEBUG("PlanB: IOCTL VIDIOCSFREQ\n");
1969                         goto unimplemented; }
1970                 case VIDIOCGFREQ: {
1971                 DEBUG("PlanB: IOCTL VIDIOCGFREQ\n");
1972                         goto unimplemented; }
1973                 case VIDIOCKEY: {
1974                 DEBUG("PlanB: IOCTL VIDIOCKEY\n");
1975                         goto unimplemented; }
1976                 case VIDIOCSAUDIO: {
1977                 DEBUG("PlanB: IOCTL VIDIOCSAUDIO\n");
1978                         goto unimplemented; }
1979                 case VIDIOCGAUDIO: {
1980                 DEBUG("PlanB: IOCTL VIDIOCGAUDIO\n");
1981                         goto unimplemented; }
1982 unimplemented:
1983                 DEBUG("       Unimplemented\n");
1984                         return -ENOIOCTLCMD;
1985         }
1986         return 0;
1987 }
1988
1989 static int planb_mmap(struct vm_area_struct *vma, struct video_device *dev, const char *adr, unsigned long size)
1990 {
1991         int i;
1992         struct planb *pb = (struct planb *)dev;
1993         unsigned long start = (unsigned long)adr;
1994
1995         if (size > MAX_GBUFFERS * PLANB_MAX_FBUF)
1996                 return -EINVAL;
1997         if (!pb->rawbuf) {
1998                 int err;
1999                 if((err=grabbuf_alloc(pb)))
2000                         return err;
2001         }
2002         for (i = 0; i < pb->rawbuf_size; i++) {
2003                 if (remap_page_range(vma, start, virt_to_phys((void *)pb->rawbuf[i]),
2004                                                 PAGE_SIZE, PAGE_SHARED))
2005                         return -EAGAIN;
2006                 start += PAGE_SIZE;
2007                 if (size <= PAGE_SIZE)
2008                         break;
2009                 size -= PAGE_SIZE;
2010         }
2011         return 0;
2012 }
2013
2014 static struct video_device planb_template=
2015 {
2016         .owner          = THIS_MODULE,
2017         .name           = PLANB_DEVICE_NAME,
2018         .type           = VID_TYPE_OVERLAY,
2019         .hardware       = VID_HARDWARE_PLANB,
2020         .open           = planb_open,
2021         .close          = planb_close,
2022         .read           = planb_read,
2023         .write          = planb_write,
2024         .ioctl          = planb_ioctl,
2025         .mmap           = planb_mmap,   /* mmap? */
2026 };
2027
2028 static int init_planb(struct planb *pb)
2029 {
2030         unsigned char saa_rev;
2031         int i, result;
2032
2033         memset ((void *) &pb->win, 0, sizeof (struct planb_window));
2034         /* Simple sanity check */
2035         if(def_norm >= NUM_SUPPORTED_NORM || def_norm < 0) {
2036                 printk(KERN_ERR "PlanB: Option(s) invalid\n");
2037                 return -2;
2038         }
2039         pb->win.norm = def_norm;
2040         pb->win.mode = PLANB_TV_MODE;   /* TV mode */
2041         pb->win.interlace=1;
2042         pb->win.x=0;
2043         pb->win.y=0;
2044         pb->win.width=768; /* 640 */
2045         pb->win.height=576; /* 480 */
2046         pb->maxlines=576;
2047 #if 0
2048         btv->win.cropwidth=768; /* 640 */
2049         btv->win.cropheight=576; /* 480 */
2050         btv->win.cropx=0;
2051         btv->win.cropy=0;
2052 #endif
2053         pb->win.pad=0;
2054         pb->win.bpp=4;
2055         pb->win.depth=32;
2056         pb->win.color_fmt=PLANB_COLOUR32;
2057         pb->win.bpl=1024*pb->win.bpp;
2058         pb->win.swidth=1024;
2059         pb->win.sheight=768;
2060 #ifdef PLANB_GSCANLINE
2061         if((pb->gbytes_per_line = PLANB_MAXPIXELS * 4) > PAGE_SIZE
2062                                 || (pb->gbytes_per_line <= 0))
2063                 return -3;
2064         else {
2065                 /* page align pb->gbytes_per_line for DMA purpose */
2066                 for(i = PAGE_SIZE; pb->gbytes_per_line < (i>>1);)
2067                         i>>=1;
2068                 pb->gbytes_per_line = i;
2069         }
2070 #endif
2071         pb->tab_size = PLANB_MAXLINES + 40;
2072         pb->suspend = 0;
2073         init_MUTEX(&pb->lock);
2074         pb->ch1_cmd = 0;
2075         pb->ch2_cmd = 0;
2076         pb->mask = 0;
2077         pb->priv_space = 0;
2078         pb->offset = 0;
2079         pb->user = 0;
2080         pb->overlay = 0;
2081         init_waitqueue_head(&pb->suspendq);
2082         pb->cmd_buff_inited = 0;
2083         pb->frame_buffer_phys = 0;
2084
2085         /* Reset DMA controllers */
2086         planb_dbdma_stop(&pb->planb_base->ch2);
2087         planb_dbdma_stop(&pb->planb_base->ch1);
2088
2089         saa_rev =  (saa_status(0, pb) & 0xf0) >> 4;
2090         printk(KERN_INFO "PlanB: SAA7196 video processor rev. %d\n", saa_rev);
2091         /* Initialize the SAA registers in memory and on chip */
2092         saa_init_regs (pb);
2093
2094         /* clear interrupt mask */
2095         pb->intr_mask = PLANB_CLR_IRQ;
2096
2097         result = request_irq(pb->irq, planb_irq, 0, "PlanB", (void *)pb);
2098         if (result < 0) {
2099                 if (result==-EINVAL)
2100                         printk(KERN_ERR "PlanB: Bad irq number (%d) "
2101                                                 "or handler\n", (int)pb->irq);
2102                 else if (result==-EBUSY)
2103                         printk(KERN_ERR "PlanB: I don't know why, "
2104                                         "but IRQ %d is busy\n", (int)pb->irq);
2105                 return result;
2106         }
2107         disable_irq(pb->irq);
2108         
2109         /* Now add the template and register the device unit. */
2110         memcpy(&pb->video_dev,&planb_template,sizeof(planb_template));
2111
2112         pb->picture.brightness=0x90<<8;
2113         pb->picture.contrast = 0x70 << 8;
2114         pb->picture.colour = 0x70<<8;
2115         pb->picture.hue = 0x8000;
2116         pb->picture.whiteness = 0;
2117         pb->picture.depth = pb->win.depth;
2118
2119         pb->frame_stat=NULL;
2120         init_waitqueue_head(&pb->capq);
2121         for(i=0; i<MAX_GBUFFERS; i++) {
2122                 pb->gbuf_idx[i] = PLANB_MAX_FBUF * i / PAGE_SIZE;
2123                 pb->gwidth[i]=0;
2124                 pb->gheight[i]=0;
2125                 pb->gfmt[i]=0;
2126                 pb->cap_cmd[i]=NULL;
2127 #ifndef PLANB_GSCANLINE
2128                 pb->l_fr_addr_idx[i] = MAX_GBUFFERS * (PLANB_MAX_FBUF
2129                                                 / PAGE_SIZE + 1) + MAX_LNUM * i;
2130                 pb->lsize[i] = 0;
2131                 pb->lnum[i] = 0;
2132 #endif
2133         }
2134         pb->rawbuf=NULL;
2135         pb->grabbing=0;
2136
2137         /* enable interrupts */
2138         out_le32(&pb->planb_base->intr_stat, PLANB_CLR_IRQ);
2139         pb->intr_mask = PLANB_FRM_IRQ;
2140         enable_irq(pb->irq);
2141
2142         if(video_register_device(&pb->video_dev, VFL_TYPE_GRABBER, video_nr)<0)
2143                 return -1;
2144
2145         return 0;
2146 }
2147
2148 /*
2149  *      Scan for a PlanB controller, request the irq and map the io memory 
2150  */
2151
2152 static int find_planb(void)
2153 {
2154         struct planb            *pb;
2155         struct device_node      *planb_devices;
2156         unsigned char           dev_fn, confreg, bus;
2157         unsigned int            old_base, new_base;
2158         unsigned int            irq;
2159         struct pci_dev          *pdev;
2160         int rc;
2161
2162         if (_machine != _MACH_Pmac)
2163                 return 0;
2164
2165         planb_devices = find_devices("planb");
2166         if (planb_devices == 0) {
2167                 planb_num=0;
2168                 printk(KERN_WARNING "PlanB: no device found!\n");
2169                 return planb_num;
2170         }
2171
2172         if (planb_devices->next != NULL)
2173                 printk(KERN_ERR "Warning: only using first PlanB device!\n");
2174         pb = &planbs[0];
2175         planb_num = 1;
2176
2177         if (planb_devices->n_addrs != 1) {
2178                 printk (KERN_WARNING "PlanB: expecting 1 address for planb "
2179                         "(got %d)", planb_devices->n_addrs);
2180                 return 0;
2181         }
2182
2183         if (planb_devices->n_intrs == 0) {
2184                 printk(KERN_WARNING "PlanB: no intrs for device %s\n",
2185                        planb_devices->full_name);
2186                 return 0;
2187         } else {
2188                 irq = planb_devices->intrs[0].line;
2189         }
2190
2191         /* Initialize PlanB's PCI registers */
2192
2193         /* There is a bug with the way OF assigns addresses
2194            to the devices behind the chaos bridge.
2195            control needs only 0x1000 of space, but decodes only
2196            the upper 16 bits. It therefore occupies a full 64K.
2197            OF assigns the planb controller memory within this space;
2198            so we need to change that here in order to access planb. */
2199
2200         /* We remap to 0xf1000000 in hope that nobody uses it ! */
2201
2202         bus = (planb_devices->addrs[0].space >> 16) & 0xff;
2203         dev_fn = (planb_devices->addrs[0].space >> 8) & 0xff;
2204         confreg = planb_devices->addrs[0].space & 0xff;
2205         old_base = planb_devices->addrs[0].address;
2206         new_base = 0xf1000000;
2207
2208         DEBUG("PlanB: Found on bus %d, dev %d, func %d, "
2209                 "membase 0x%x (base reg. 0x%x)\n",
2210                 bus, PCI_SLOT(dev_fn), PCI_FUNC(dev_fn), old_base, confreg);
2211
2212         pdev = pci_find_slot (bus, dev_fn);
2213         if (!pdev) {
2214                 printk(KERN_ERR "planb: cannot find slot\n");
2215                 goto err_out;
2216         }
2217
2218         /* Enable response in memory space, bus mastering,
2219            use memory write and invalidate */
2220         rc = pci_enable_device(pdev);
2221         if (rc) {
2222                 printk(KERN_ERR "planb: cannot enable PCI device %s\n",
2223                        pci_name(pdev));
2224                 goto err_out;
2225         }
2226         rc = pci_set_mwi(pdev);
2227         if (rc) {
2228                 printk(KERN_ERR "planb: cannot enable MWI on PCI device %s\n",
2229                        pci_name(pdev));
2230                 goto err_out_disable;
2231         }
2232         pci_set_master(pdev);
2233
2234         /* Set the new base address */
2235         pci_write_config_dword (pdev, confreg, new_base);
2236
2237         planb_regs = (volatile struct planb_registers *)
2238                                                 ioremap (new_base, 0x400);
2239         pb->planb_base = planb_regs;
2240         pb->planb_base_phys = (struct planb_registers *)new_base;
2241         pb->irq = irq;
2242         
2243         return planb_num;
2244
2245 err_out_disable:
2246         pci_disable_device(pdev);
2247 err_out:
2248         /* FIXME handle error */   /* comment moved from pci_find_slot, above */
2249         return 0;
2250 }
2251
2252 static void release_planb(void)
2253 {
2254         int i;
2255         struct planb *pb;
2256
2257         for (i=0;i<planb_num; i++) 
2258         {
2259                 pb=&planbs[i];
2260
2261                 /* stop and flash DMAs unconditionally */
2262                 planb_dbdma_stop(&pb->planb_base->ch2);
2263                 planb_dbdma_stop(&pb->planb_base->ch1);
2264
2265                 /* clear and free interrupts */
2266                 pb->intr_mask = PLANB_CLR_IRQ;
2267                 out_le32 (&pb->planb_base->intr_stat, PLANB_CLR_IRQ);
2268                 free_irq(pb->irq, pb);
2269
2270                 /* make sure all allocated memory are freed */
2271                 planb_prepare_close(pb);
2272
2273                 printk(KERN_INFO "PlanB: unregistering with v4l\n");
2274                 video_unregister_device(&pb->video_dev);
2275
2276                 /* note that iounmap() does nothing on the PPC right now */
2277                 iounmap ((void *)pb->planb_base);
2278         }
2279 }
2280
2281 static int __init init_planbs(void)
2282 {
2283         int i;
2284   
2285         if (find_planb()<=0)
2286                 return -EIO;
2287
2288         for (i=0; i<planb_num; i++) {
2289                 if (init_planb(&planbs[i])<0) {
2290                         printk(KERN_ERR "PlanB: error registering device %d"
2291                                                         " with v4l\n", i);
2292                         release_planb();
2293                         return -EIO;
2294                 } 
2295                 printk(KERN_INFO "PlanB: registered device %d with v4l\n", i);
2296         }  
2297         return 0;
2298 }
2299
2300 static void __exit exit_planbs(void)
2301 {
2302         release_planb();
2303 }
2304
2305 module_init(init_planbs);
2306 module_exit(exit_planbs);