vserver 1.9.5.x5
[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         msleep_interruptible(30);
182
183         return (unsigned char)in_8 (&planb_regs->saa_status);
184 }
185
186 static void saa_set(unsigned char addr, unsigned char val, struct planb *pb)
187 {
188         if(saa_regs[pb->win.norm][addr] != val) {
189                 saa_regs[pb->win.norm][addr] = val;
190                 saa_write_reg (addr, val);
191         }
192         return;
193 }
194
195 static void saa_init_regs(struct planb *pb)
196 {
197         int i;
198
199         for (i = 0; i < SAA7196_NUMREGS; i++)
200                 saa_write_reg (i, saa_regs[pb->win.norm][i]);
201 }
202
203 static unsigned int saa_geo_setup(int width, int height, int interlace, int bpp,
204         struct planb *pb)
205 {
206         int ht, norm = pb->win.norm;
207
208         switch(bpp) {
209         case 2:
210                 /* RGB555+a 1x16-bit + 16-bit transparent */
211                 saa_regs[norm][SAA7196_FMTS] &= ~0x3;
212                 break;
213         case 1:
214         case 4:
215                 /* RGB888 1x24-bit + 8-bit transparent */
216                 saa_regs[norm][SAA7196_FMTS] &= ~0x1;
217                 saa_regs[norm][SAA7196_FMTS] |= 0x2;
218                 break;
219         default:
220                 return -EINVAL;
221         }
222         ht = (interlace ? height / 2 : height);
223         saa_regs[norm][SAA7196_OUTPIX] = (unsigned char) (width & 0x00ff);
224         saa_regs[norm][SAA7196_HFILT] = (saa_regs[norm][SAA7196_HFILT] & ~0x3)
225                                                 | (width >> 8 & 0x3);
226         saa_regs[norm][SAA7196_OUTLINE] = (unsigned char) (ht & 0xff);
227         saa_regs[norm][SAA7196_VYP] = (saa_regs[norm][SAA7196_VYP] & ~0x3)
228                                                 | (ht >> 8 & 0x3);
229         /* feed both fields if interlaced, or else feed only even fields */
230         saa_regs[norm][SAA7196_FMTS] = (interlace) ?
231                                         (saa_regs[norm][SAA7196_FMTS] & ~0x60)
232                                         : (saa_regs[norm][SAA7196_FMTS] | 0x60);
233         /* transparent mode; extended format enabled */
234         saa_regs[norm][SAA7196_DPATH] |= 0x3;
235
236         return 0;
237 }
238
239 /***************************/
240 /* DBDMA support functions */
241 /***************************/
242
243 static inline void planb_dbdma_restart(volatile struct dbdma_regs *ch)
244 {
245         out_le32(&ch->control, PLANB_CLR(RUN));
246         out_le32(&ch->control, PLANB_SET(RUN|WAKE) | PLANB_CLR(PAUSE));
247 }
248
249 static inline void planb_dbdma_stop(volatile struct dbdma_regs *ch)
250 {
251         int i = 0;
252
253         out_le32(&ch->control, PLANB_CLR(RUN) | PLANB_SET(FLUSH));
254         while((in_le32(&ch->status) == (ACTIVE | FLUSH)) && (i < 999)) {
255                 IDEBUG("PlanB: waiting for DMA to stop\n");
256                 i++;
257         }
258 }
259
260 static inline void tab_cmd_dbdma(volatile struct dbdma_cmd *ch,
261         unsigned short command, unsigned int cmd_dep)
262 {
263         st_le16(&ch->command, command);
264         st_le32(&ch->cmd_dep, cmd_dep);
265 }
266
267 static inline void tab_cmd_store(volatile struct dbdma_cmd *ch,
268         unsigned int phy_addr, unsigned int cmd_dep)
269 {
270         st_le16(&ch->command, STORE_WORD | KEY_SYSTEM);
271         st_le16(&ch->req_count, 4);
272         st_le32(&ch->phy_addr, phy_addr);
273         st_le32(&ch->cmd_dep, cmd_dep);
274 }
275
276 static inline void tab_cmd_gen(volatile struct dbdma_cmd *ch,
277         unsigned short command, unsigned short req_count,
278         unsigned int phy_addr, unsigned int cmd_dep)
279 {
280         st_le16(&ch->command, command);
281         st_le16(&ch->req_count, req_count);
282         st_le32(&ch->phy_addr, phy_addr);
283         st_le32(&ch->cmd_dep, cmd_dep);
284 }
285
286 static volatile struct dbdma_cmd *cmd_geo_setup(
287         volatile struct dbdma_cmd *c1, int width, int height, int interlace,
288         int bpp, int clip, struct planb *pb)
289 {
290         int norm = pb->win.norm;
291
292         if((saa_geo_setup(width, height, interlace, bpp, pb)) != 0)
293                 return (volatile struct dbdma_cmd *)NULL;
294         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),
295                                                         SAA7196_FMTS);
296         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),
297                                         saa_regs[norm][SAA7196_FMTS]);
298         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),
299                                                         SAA7196_DPATH);
300         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),
301                                         saa_regs[norm][SAA7196_DPATH]);
302         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->even),
303                                         bpp | ((clip)? PLANB_CLIPMASK: 0));
304         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->odd),
305                                         bpp | ((clip)? PLANB_CLIPMASK: 0));
306         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),
307                                                         SAA7196_OUTPIX);
308         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),
309                                         saa_regs[norm][SAA7196_OUTPIX]);
310         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),
311                                                         SAA7196_HFILT);
312         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),
313                                         saa_regs[norm][SAA7196_HFILT]);
314         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),
315                                                         SAA7196_OUTLINE);
316         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),
317                                         saa_regs[norm][SAA7196_OUTLINE]);
318         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),
319                                                         SAA7196_VYP);
320         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),
321                                         saa_regs[norm][SAA7196_VYP]);
322         return c1;
323 }
324
325 /******************************/
326 /* misc. supporting functions */
327 /******************************/
328
329 static inline void planb_lock(struct planb *pb)
330 {
331         down(&pb->lock);
332 }
333
334 static inline void planb_unlock(struct planb *pb)
335 {
336         up(&pb->lock);
337 }
338
339 /***************/
340 /* Driver Core */
341 /***************/
342
343 static int planb_prepare_open(struct planb *pb)
344 {
345         int     i, size;
346
347         /* allocate memory for two plus alpha command buffers (size: max lines,
348            plus 40 commands handling, plus 1 alignment), plus dummy command buf,
349            plus clipmask buffer, plus frame grabbing status */
350         size = (pb->tab_size*(2+MAX_GBUFFERS*TAB_FACTOR)+1+MAX_GBUFFERS
351                 * PLANB_DUMMY)*sizeof(struct dbdma_cmd)
352                 +(PLANB_MAXLINES*((PLANB_MAXPIXELS+7)& ~7))/8
353                 +MAX_GBUFFERS*sizeof(unsigned int);
354         if ((pb->priv_space = kmalloc (size, GFP_KERNEL)) == 0)
355                 return -ENOMEM;
356         memset ((void *) pb->priv_space, 0, size);
357         pb->overlay_last1 = pb->ch1_cmd = (volatile struct dbdma_cmd *)
358                                                 DBDMA_ALIGN (pb->priv_space);
359         pb->overlay_last2 = pb->ch2_cmd = pb->ch1_cmd + pb->tab_size;
360         pb->ch1_cmd_phys = virt_to_bus(pb->ch1_cmd);
361         pb->cap_cmd[0] = pb->ch2_cmd + pb->tab_size;
362         pb->pre_cmd[0] = pb->cap_cmd[0] + pb->tab_size * TAB_FACTOR;
363         for (i = 1; i < MAX_GBUFFERS; i++) {
364                 pb->cap_cmd[i] = pb->pre_cmd[i-1] + PLANB_DUMMY;
365                 pb->pre_cmd[i] = pb->cap_cmd[i] + pb->tab_size * TAB_FACTOR;
366         }
367         pb->frame_stat=(volatile unsigned int *)(pb->pre_cmd[MAX_GBUFFERS-1]
368                                                 + PLANB_DUMMY);
369         pb->mask = (unsigned char *)(pb->frame_stat+MAX_GBUFFERS);
370
371         pb->rawbuf = NULL;
372         pb->rawbuf_size = 0;
373         pb->grabbing = 0;
374         for (i = 0; i < MAX_GBUFFERS; i++) {
375                 pb->frame_stat[i] = GBUFFER_UNUSED;
376                 pb->gwidth[i] = 0;
377                 pb->gheight[i] = 0;
378                 pb->gfmt[i] = 0;
379                 pb->gnorm_switch[i] = 0;
380 #ifndef PLANB_GSCANLINE
381                 pb->lsize[i] = 0;
382                 pb->lnum[i] = 0;
383 #endif /* PLANB_GSCANLINE */
384         }
385         pb->gcount = 0;
386         pb->suspend = 0;
387         pb->last_fr = -999;
388         pb->prev_last_fr = -999;
389
390         /* Reset DMA controllers */
391         planb_dbdma_stop(&pb->planb_base->ch2);
392         planb_dbdma_stop(&pb->planb_base->ch1);
393
394         return 0;
395 }
396
397 static void planb_prepare_close(struct planb *pb)
398 {
399         int i;
400
401         /* make sure the dma's are idle */
402         planb_dbdma_stop(&pb->planb_base->ch2);
403         planb_dbdma_stop(&pb->planb_base->ch1);
404         /* free kernel memory of command buffers */
405         if(pb->priv_space != 0) {
406                 kfree (pb->priv_space);
407                 pb->priv_space = 0;
408                 pb->cmd_buff_inited = 0;
409         }
410         if(pb->rawbuf) {
411                 for (i = 0; i < pb->rawbuf_size; i++) {
412                         ClearPageReserved(virt_to_page(pb->rawbuf[i]));
413                         free_pages((unsigned long)pb->rawbuf[i], 0);
414                 }
415                 kfree(pb->rawbuf);
416         }
417         pb->rawbuf = NULL;
418 }
419
420 /*****************************/
421 /* overlay support functions */
422 /*****************************/
423
424 static void overlay_start(struct planb *pb)
425 {
426
427         DEBUG("PlanB: overlay_start()\n");
428
429         if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) {
430
431                 DEBUG("PlanB: presumably, grabbing is in progress...\n");
432
433                 planb_dbdma_stop(&pb->planb_base->ch2);
434                 out_le32 (&pb->planb_base->ch2.cmdptr,
435                                                 virt_to_bus(pb->ch2_cmd));
436                 planb_dbdma_restart(&pb->planb_base->ch2);
437                 st_le16 (&pb->ch1_cmd->command, DBDMA_NOP);
438                 tab_cmd_dbdma(pb->last_cmd[pb->last_fr],
439                                         DBDMA_NOP | BR_ALWAYS,
440                                         virt_to_bus(pb->ch1_cmd));
441                 eieio();
442                 pb->prev_last_fr = pb->last_fr;
443                 pb->last_fr = -2;
444                 if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) {
445                         IDEBUG("PlanB: became inactive "
446                                 "in the mean time... reactivating\n");
447                         planb_dbdma_stop(&pb->planb_base->ch1);
448                         out_le32 (&pb->planb_base->ch1.cmdptr,
449                                                 virt_to_bus(pb->ch1_cmd));
450                         planb_dbdma_restart(&pb->planb_base->ch1);
451                 }
452         } else {
453
454                 DEBUG("PlanB: currently idle, so can do whatever\n");
455
456                 planb_dbdma_stop(&pb->planb_base->ch2);
457                 planb_dbdma_stop(&pb->planb_base->ch1);
458                 st_le32 (&pb->planb_base->ch2.cmdptr,
459                                                 virt_to_bus(pb->ch2_cmd));
460                 st_le32 (&pb->planb_base->ch1.cmdptr,
461                                                 virt_to_bus(pb->ch1_cmd));
462                 out_le16 (&pb->ch1_cmd->command, DBDMA_NOP);
463                 planb_dbdma_restart(&pb->planb_base->ch2);
464                 planb_dbdma_restart(&pb->planb_base->ch1);
465                 pb->last_fr = -1;
466         }
467         return;
468 }
469
470 static void overlay_stop(struct planb *pb)
471 {
472         DEBUG("PlanB: overlay_stop()\n");
473
474         if(pb->last_fr == -1) {
475
476                 DEBUG("PlanB: no grabbing, it seems...\n");
477
478                 planb_dbdma_stop(&pb->planb_base->ch2);
479                 planb_dbdma_stop(&pb->planb_base->ch1);
480                 pb->last_fr = -999;
481         } else if(pb->last_fr == -2) {
482                 unsigned int cmd_dep;
483                 tab_cmd_dbdma(pb->cap_cmd[pb->prev_last_fr], DBDMA_STOP, 0);
484                 eieio();
485                 cmd_dep = (unsigned int)in_le32(&pb->overlay_last1->cmd_dep);
486                 if(overlay_is_active(pb)) {
487
488                         DEBUG("PlanB: overlay is currently active\n");
489
490                         planb_dbdma_stop(&pb->planb_base->ch2);
491                         planb_dbdma_stop(&pb->planb_base->ch1);
492                         if(cmd_dep != pb->ch1_cmd_phys) {
493                                 out_le32(&pb->planb_base->ch1.cmdptr,
494                                                 virt_to_bus(pb->overlay_last1));
495                                 planb_dbdma_restart(&pb->planb_base->ch1);
496                         }
497                 }
498                 pb->last_fr = pb->prev_last_fr;
499                 pb->prev_last_fr = -999;
500         }
501         return;
502 }
503
504 static void suspend_overlay(struct planb *pb)
505 {
506         int fr = -1;
507         struct dbdma_cmd last;
508
509         DEBUG("PlanB: suspend_overlay: %d\n", pb->suspend);
510
511         if(pb->suspend++)
512                 return;
513         if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) {
514                 if(pb->last_fr == -2) {
515                         fr = pb->prev_last_fr;
516                         memcpy(&last, (void*)pb->last_cmd[fr], sizeof(last));
517                         tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0);
518                 }
519                 if(overlay_is_active(pb)) {
520                         planb_dbdma_stop(&pb->planb_base->ch2);
521                         planb_dbdma_stop(&pb->planb_base->ch1);
522                         pb->suspended.overlay = 1;
523                         pb->suspended.frame = fr;
524                         memcpy(&pb->suspended.cmd, &last, sizeof(last));
525                         return;
526                 }
527         }
528         pb->suspended.overlay = 0;
529         pb->suspended.frame = fr;
530         memcpy(&pb->suspended.cmd, &last, sizeof(last));
531         return;
532 }
533
534 static void resume_overlay(struct planb *pb)
535 {
536
537         DEBUG("PlanB: resume_overlay: %d\n", pb->suspend);
538
539         if(pb->suspend > 1)
540                 return;
541         if(pb->suspended.frame != -1) {
542                 memcpy((void*)pb->last_cmd[pb->suspended.frame],
543                                 &pb->suspended.cmd, sizeof(pb->suspended.cmd));
544         }
545         if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) {
546                 goto finish;
547         }
548         if(pb->suspended.overlay) {
549
550                 DEBUG("PlanB: overlay being resumed\n");
551
552                 st_le16 (&pb->ch1_cmd->command, DBDMA_NOP);
553                 st_le16 (&pb->ch2_cmd->command, DBDMA_NOP);
554                 /* Set command buffer addresses */
555                 st_le32(&pb->planb_base->ch1.cmdptr,
556                                         virt_to_bus(pb->overlay_last1));
557                 out_le32(&pb->planb_base->ch2.cmdptr,
558                                         virt_to_bus(pb->overlay_last2));
559                 /* Start the DMA controller */
560                 out_le32 (&pb->planb_base->ch2.control,
561                                 PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE));
562                 out_le32 (&pb->planb_base->ch1.control,
563                                 PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE));
564         } else if(pb->suspended.frame != -1) {
565                 out_le32(&pb->planb_base->ch1.cmdptr,
566                                 virt_to_bus(pb->last_cmd[pb->suspended.frame]));
567                 out_le32 (&pb->planb_base->ch1.control,
568                                 PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE));
569         }
570
571 finish:
572         pb->suspend--;
573         wake_up_interruptible(&pb->suspendq);
574 }
575
576 static void add_clip(struct planb *pb, struct video_clip *clip) 
577 {
578         volatile unsigned char  *base;
579         int     xc = clip->x, yc = clip->y;
580         int     wc = clip->width, hc = clip->height;
581         int     ww = pb->win.width, hw = pb->win.height;
582         int     x, y, xtmp1, xtmp2;
583
584         DEBUG("PlanB: clip %dx%d+%d+%d\n", wc, hc, xc, yc);
585
586         if(xc < 0) {
587                 wc += xc;
588                 xc = 0;
589         }
590         if(yc < 0) {
591                 hc += yc;
592                 yc = 0;
593         }
594         if(xc + wc > ww)
595                 wc = ww - xc;
596         if(wc <= 0) /* Nothing to do */
597                 return;
598         if(yc + hc > hw)
599                 hc = hw - yc;
600
601         for (y = yc; y < yc+hc; y++) {
602                 xtmp1=xc>>3;
603                 xtmp2=(xc+wc)>>3;
604                 base = pb->mask + y*96;
605                 if(xc != 0 || wc >= 8)
606                         *(base + xtmp1) &= (unsigned char)(0x00ff &
607                                 (0xff00 >> (xc&7)));
608                 for (x = xtmp1 + 1; x < xtmp2; x++) {
609                         *(base + x) = 0;
610                 }
611                 if(xc < (ww & ~0x7))
612                         *(base + xtmp2) &= (unsigned char)(0x00ff >>
613                                 ((xc+wc) & 7));
614         }
615
616         return;
617 }
618
619 static void fill_cmd_buff(struct planb *pb)
620 {
621         int restore = 0;
622         volatile struct dbdma_cmd last;
623
624         DEBUG("PlanB: fill_cmd_buff()\n");
625
626         if(pb->overlay_last1 != pb->ch1_cmd) {
627                 restore = 1;
628                 last = *(pb->overlay_last1);
629         }
630         memset ((void *) pb->ch1_cmd, 0, 2 * pb->tab_size
631                                         * sizeof(struct dbdma_cmd));
632         cmd_buff (pb);
633         if(restore)
634                 *(pb->overlay_last1) = last;
635         if(pb->suspended.overlay) {
636                 unsigned long jump_addr = in_le32(&pb->overlay_last1->cmd_dep);
637                 if(jump_addr != pb->ch1_cmd_phys) {
638                         int i;
639
640                         DEBUG("PlanB: adjusting ch1's jump address\n");
641
642                         for(i = 0; i < MAX_GBUFFERS; i++) {
643                                 if(pb->need_pre_capture[i]) {
644                                     if(jump_addr == virt_to_bus(pb->pre_cmd[i]))
645                                         goto found;
646                                 } else {
647                                     if(jump_addr == virt_to_bus(pb->cap_cmd[i]))
648                                         goto found;
649                                 }
650                         }
651
652                         DEBUG("PlanB: not found...\n");
653
654                         goto out;
655 found:
656                         if(pb->need_pre_capture[i])
657                                 out_le32(&pb->pre_cmd[i]->phy_addr,
658                                                 virt_to_bus(pb->overlay_last1));
659                         else
660                                 out_le32(&pb->cap_cmd[i]->phy_addr,
661                                                 virt_to_bus(pb->overlay_last1));
662                 }
663         }
664 out:
665         pb->cmd_buff_inited = 1;
666
667         return;
668 }
669
670 static void cmd_buff(struct planb *pb)
671 {
672         int             i, bpp, count, nlines, stepsize, interlace;
673         unsigned long   base, jump, addr_com, addr_dep;
674         volatile struct dbdma_cmd *c1 = pb->ch1_cmd;
675         volatile struct dbdma_cmd *c2 = pb->ch2_cmd;
676
677         interlace = pb->win.interlace;
678         bpp = pb->win.bpp;
679         count = (bpp * ((pb->win.x + pb->win.width > pb->win.swidth) ?
680                 (pb->win.swidth - pb->win.x) : pb->win.width));
681         nlines = ((pb->win.y + pb->win.height > pb->win.sheight) ?
682                 (pb->win.sheight - pb->win.y) : pb->win.height);
683
684         /* Do video in: */
685
686         /* Preamble commands: */
687         addr_com = virt_to_bus(c1);
688         addr_dep = virt_to_bus(&c1->cmd_dep);
689         tab_cmd_dbdma(c1++, DBDMA_NOP, 0);
690         jump = virt_to_bus(c1+16); /* 14 by cmd_geo_setup() and 2 for padding */
691         if((c1 = cmd_geo_setup(c1, pb->win.width, pb->win.height, interlace,
692                                         bpp, 1, pb)) == NULL) {
693                 printk(KERN_WARNING "PlanB: encountered serious problems\n");
694                 tab_cmd_dbdma(pb->ch1_cmd + 1, DBDMA_STOP, 0);
695                 tab_cmd_dbdma(pb->ch2_cmd + 1, DBDMA_STOP, 0);
696                 return;
697         }
698         tab_cmd_store(c1++, addr_com, (unsigned)(DBDMA_NOP | BR_ALWAYS) << 16);
699         tab_cmd_store(c1++, addr_dep, jump);
700         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel),
701                                                         PLANB_SET(FIELD_SYNC));
702                 /* (1) wait for field sync to be set */
703         tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
704         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
705                                                         PLANB_SET(ODD_FIELD));
706                 /* wait for field sync to be cleared */
707         tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
708                 /* if not odd field, wait until field sync is set again */
709         tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++;
710                 /* assert ch_sync to ch2 */
711         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch2.control),
712                                                         PLANB_SET(CH_SYNC));
713         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
714                                                         PLANB_SET(DMA_ABORT));
715
716         base = (pb->frame_buffer_phys + pb->offset + pb->win.y * (pb->win.bpl
717                                         + pb->win.pad) + pb->win.x * bpp);
718
719         if (interlace) {
720                 stepsize = 2;
721                 jump = virt_to_bus(c1 + (nlines + 1) / 2);
722         } else {
723                 stepsize = 1;
724                 jump = virt_to_bus(c1 + nlines);
725         }
726
727         /* even field data: */
728         for (i=0; i < nlines; i += stepsize, c1++)
729                 tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET,
730                         count, base + i * (pb->win.bpl + pb->win.pad), jump);
731
732         /* For non-interlaced, we use even fields only */
733         if (!interlace)
734                 goto cmd_tab_data_end;
735
736         /* Resync to odd field */
737                 /* (2) wait for field sync to be set */
738         tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
739         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
740                                                         PLANB_SET(ODD_FIELD));
741                 /* wait for field sync to be cleared */
742         tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
743                 /* if not odd field, wait until field sync is set again */
744         tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++;
745                 /* assert ch_sync to ch2 */
746         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch2.control),
747                                                         PLANB_SET(CH_SYNC));
748         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
749                                                         PLANB_SET(DMA_ABORT));
750         
751         /* odd field data: */
752         jump = virt_to_bus(c1 + nlines / 2);
753         for (i=1; i < nlines; i += stepsize, c1++)
754                 tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count,
755                         base + i * (pb->win.bpl + pb->win.pad), jump);
756
757         /* And jump back to the start */
758 cmd_tab_data_end:
759         pb->overlay_last1 = c1; /* keep a pointer to the last command */
760         tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->ch1_cmd));
761
762         /* Clipmask command buffer */
763
764         /* Preamble commands: */
765         tab_cmd_dbdma(c2++, DBDMA_NOP, 0);
766         tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.wait_sel),
767                                                         PLANB_SET(CH_SYNC));
768                 /* wait until ch1 asserts ch_sync */
769         tab_cmd_dbdma(c2++, DBDMA_NOP | WAIT_IFCLR, 0);
770                 /* clear ch_sync asserted by ch1 */
771         tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.control),
772                                                         PLANB_CLR(CH_SYNC));
773         tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.wait_sel),
774                                                         PLANB_SET(FIELD_SYNC));
775         tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel),
776                                                         PLANB_SET(ODD_FIELD));
777
778         /* jump to end of even field if appropriate */
779         /* this points to (interlace)? pos. C: pos. B */
780         jump = (interlace) ? virt_to_bus(c2 + (nlines + 1) / 2 + 2):
781                                                 virt_to_bus(c2 + nlines + 2);
782                 /* if odd field, skip over to odd field clipmasking */
783         tab_cmd_dbdma(c2++, DBDMA_NOP | BR_IFSET, jump);
784
785         /* even field mask: */
786         tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel),
787                                                         PLANB_SET(DMA_ABORT));
788         /* this points to pos. B */
789         jump = (interlace) ? virt_to_bus(c2 + nlines + 1):
790                                                 virt_to_bus(c2 + nlines);
791         base = virt_to_bus(pb->mask);
792         for (i=0; i < nlines; i += stepsize, c2++)
793                 tab_cmd_gen(c2, OUTPUT_MORE | KEY_STREAM0 | BR_IFSET, 96,
794                         base + i * 96, jump);
795
796         /* For non-interlaced, we use only even fields */
797         if(!interlace)
798                 goto cmd_tab_mask_end;
799
800         /* odd field mask: */
801 /* C */ tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel),
802                                                         PLANB_SET(DMA_ABORT));
803         /* this points to pos. B */
804         jump = virt_to_bus(c2 + nlines / 2);
805         base = virt_to_bus(pb->mask);
806         for (i=1; i < nlines; i += 2, c2++)     /* abort if set */
807                 tab_cmd_gen(c2, OUTPUT_MORE | KEY_STREAM0 | BR_IFSET, 96,
808                         base + i * 96, jump);
809
810         /* Inform channel 1 and jump back to start */
811 cmd_tab_mask_end:
812         /* ok, I just realized this is kind of flawed. */
813         /* this part is reached only after odd field clipmasking. */
814         /* wanna clean up? */
815                 /* wait for field sync to be set */
816                 /* corresponds to fsync (1) of ch1 */
817 /* B */ tab_cmd_dbdma(c2++, DBDMA_NOP | WAIT_IFCLR, 0);
818                 /* restart ch1, meant to clear any dead bit or something */
819         tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch1.control),
820                                                         PLANB_CLR(RUN));
821         tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch1.control),
822                                                         PLANB_SET(RUN));
823         pb->overlay_last2 = c2; /* keep a pointer to the last command */
824                 /* start over even field clipmasking */
825         tab_cmd_dbdma(c2, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->ch2_cmd));
826
827         eieio();
828         return;
829 }
830
831 /*********************************/
832 /* grabdisplay support functions */
833 /*********************************/
834
835 static int palette2fmt[] = {
836        0,
837        PLANB_GRAY,
838        0,
839        0,
840        0,
841        PLANB_COLOUR32,
842        PLANB_COLOUR15,
843        0,
844        0,
845        0,
846        0,
847        0,
848        0,
849        0,
850        0,
851 };
852
853 #define PLANB_PALETTE_MAX 15
854
855 static inline int overlay_is_active(struct planb *pb)
856 {
857         unsigned int size = pb->tab_size * sizeof(struct dbdma_cmd);
858         unsigned int caddr = (unsigned)in_le32(&pb->planb_base->ch1.cmdptr);
859
860         return (in_le32(&pb->overlay_last1->cmd_dep) == pb->ch1_cmd_phys)
861                         && (caddr < (pb->ch1_cmd_phys + size))
862                         && (caddr >= (unsigned)pb->ch1_cmd_phys);
863 }
864
865 static int vgrab(struct planb *pb, struct video_mmap *mp)
866 {
867         unsigned int fr = mp->frame;
868         unsigned int format;
869
870         if(pb->rawbuf==NULL) {
871                 int err;
872                 if((err=grabbuf_alloc(pb)))
873                         return err;
874         }
875
876         IDEBUG("PlanB: grab %d: %dx%d(%u)\n", pb->grabbing,
877                                                 mp->width, mp->height, fr);
878
879         if(pb->grabbing >= MAX_GBUFFERS)
880                 return -ENOBUFS;
881         if(fr > (MAX_GBUFFERS - 1) || fr < 0)
882                 return -EINVAL;
883         if(mp->height <= 0 || mp->width <= 0)
884                 return -EINVAL;
885         if(mp->format < 0 || mp->format >= PLANB_PALETTE_MAX)
886                 return -EINVAL;
887         if((format = palette2fmt[mp->format]) == 0)
888                 return -EINVAL;
889         if (mp->height * mp->width * format > PLANB_MAX_FBUF) /* format = bpp */
890                 return -EINVAL;
891
892         planb_lock(pb);
893         if(mp->width != pb->gwidth[fr] || mp->height != pb->gheight[fr] ||
894                         format != pb->gfmt[fr] || (pb->gnorm_switch[fr])) {
895                 int i;
896 #ifndef PLANB_GSCANLINE
897                 unsigned int osize = pb->gwidth[fr] * pb->gheight[fr]
898                                                                 * pb->gfmt[fr];
899                 unsigned int nsize = mp->width * mp->height * format;
900 #endif
901
902                 IDEBUG("PlanB: gwidth = %d, gheight = %d, mp->format = %u\n",
903                                         mp->width, mp->height, mp->format);
904
905 #ifndef PLANB_GSCANLINE
906                 if(pb->gnorm_switch[fr])
907                         nsize = 0;
908                 if (nsize < osize) {
909                         for(i = pb->gbuf_idx[fr]; osize > 0; i++) {
910                                 memset((void *)pb->rawbuf[i], 0, PAGE_SIZE);
911                                 osize -= PAGE_SIZE;
912                         }
913                 }
914                 for(i = pb->l_fr_addr_idx[fr]; i < pb->l_fr_addr_idx[fr]
915                                                         + pb->lnum[fr]; i++)
916                         memset((void *)pb->rawbuf[i], 0, PAGE_SIZE);
917 #else
918 /* XXX TODO */
919 /*
920                 if(pb->gnorm_switch[fr])
921                         memset((void *)pb->gbuffer[fr], 0,
922                                         pb->gbytes_per_line * pb->gheight[fr]);
923                 else {
924                         if(mp->
925                         for(i = 0; i < pb->gheight[fr]; i++) {
926                                 memset((void *)(pb->gbuffer[fr]
927                                         + pb->gbytes_per_line * i
928                         }
929                 }
930 */
931 #endif
932                 pb->gwidth[fr] = mp->width;
933                 pb->gheight[fr] = mp->height;
934                 pb->gfmt[fr] = format;
935                 pb->last_cmd[fr] = setup_grab_cmd(fr, pb);
936                 planb_pre_capture(fr, pb->gfmt[fr], pb); /* gfmt = bpp */
937                 pb->need_pre_capture[fr] = 1;
938                 pb->gnorm_switch[fr] = 0;
939         } else
940                 pb->need_pre_capture[fr] = 0;
941         pb->frame_stat[fr] = GBUFFER_GRABBING;
942         if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) {
943
944                 IDEBUG("PlanB: ch1 inactive, initiating grabbing\n");
945
946                 planb_dbdma_stop(&pb->planb_base->ch1);
947                 if(pb->need_pre_capture[fr]) {
948
949                         IDEBUG("PlanB: padding pre-capture sequence\n");
950
951                         out_le32 (&pb->planb_base->ch1.cmdptr,
952                                                 virt_to_bus(pb->pre_cmd[fr]));
953                 } else {
954                         tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0);
955                         tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0);
956                 /* let's be on the safe side. here is not timing critical. */
957                         tab_cmd_dbdma((pb->cap_cmd[fr] + 1), DBDMA_NOP, 0);
958                         out_le32 (&pb->planb_base->ch1.cmdptr,
959                                                 virt_to_bus(pb->cap_cmd[fr]));
960                 }
961                 planb_dbdma_restart(&pb->planb_base->ch1);
962                 pb->last_fr = fr;
963         } else {
964                 int i;
965
966                 IDEBUG("PlanB: ch1 active, grabbing being queued\n");
967
968                 if((pb->last_fr == -1) || ((pb->last_fr == -2) &&
969                                                 overlay_is_active(pb))) {
970
971                         IDEBUG("PlanB: overlay is active, grabbing defered\n");
972
973                         tab_cmd_dbdma(pb->last_cmd[fr],
974                                         DBDMA_NOP | BR_ALWAYS,
975                                         virt_to_bus(pb->ch1_cmd));
976                         if(pb->need_pre_capture[fr]) {
977
978                                 IDEBUG("PlanB: padding pre-capture sequence\n");
979
980                                 tab_cmd_store(pb->pre_cmd[fr],
981                                     virt_to_bus(&pb->overlay_last1->cmd_dep),
982                                                 virt_to_bus(pb->ch1_cmd));
983                                 eieio();
984                                 out_le32 (&pb->overlay_last1->cmd_dep,
985                                                 virt_to_bus(pb->pre_cmd[fr]));
986                         } else {
987                                 tab_cmd_store(pb->cap_cmd[fr],
988                                     virt_to_bus(&pb->overlay_last1->cmd_dep),
989                                                 virt_to_bus(pb->ch1_cmd));
990                                 tab_cmd_dbdma((pb->cap_cmd[fr] + 1),
991                                                                 DBDMA_NOP, 0);
992                                 eieio();
993                                 out_le32 (&pb->overlay_last1->cmd_dep,
994                                                 virt_to_bus(pb->cap_cmd[fr]));
995                         }
996                         for(i = 0; overlay_is_active(pb) && i < 999; i++)
997                                 IDEBUG("PlanB: waiting for overlay done\n");
998                         tab_cmd_dbdma(pb->ch1_cmd, DBDMA_NOP, 0);
999                         pb->prev_last_fr = fr;
1000                         pb->last_fr = -2;
1001                 } else if(pb->last_fr == -2) {
1002
1003                         IDEBUG("PlanB: mixed mode detected, grabbing"
1004                                 " will be done before activating overlay\n");
1005
1006                         tab_cmd_dbdma(pb->ch1_cmd, DBDMA_NOP, 0);
1007                         if(pb->need_pre_capture[fr]) {
1008
1009                                 IDEBUG("PlanB: padding pre-capture sequence\n");
1010
1011                                 tab_cmd_dbdma(pb->last_cmd[pb->prev_last_fr],
1012                                                 DBDMA_NOP | BR_ALWAYS,
1013                                                 virt_to_bus(pb->pre_cmd[fr]));
1014                                 eieio();
1015                         } else {
1016                                 tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0);
1017                                 if(pb->gwidth[pb->prev_last_fr] !=
1018                                                                 pb->gwidth[fr]
1019                                         || pb->gheight[pb->prev_last_fr] !=
1020                                                                 pb->gheight[fr]
1021                                         || pb->gfmt[pb->prev_last_fr] !=
1022                                                                 pb->gfmt[fr])
1023                                         tab_cmd_dbdma((pb->cap_cmd[fr] + 1),
1024                                                                 DBDMA_NOP, 0);
1025                                 else
1026                                         tab_cmd_dbdma((pb->cap_cmd[fr] + 1),
1027                                             DBDMA_NOP | BR_ALWAYS,
1028                                             virt_to_bus(pb->cap_cmd[fr] + 16));
1029                                 tab_cmd_dbdma(pb->last_cmd[pb->prev_last_fr],
1030                                                 DBDMA_NOP | BR_ALWAYS,
1031                                                 virt_to_bus(pb->cap_cmd[fr]));
1032                                 eieio();
1033                         }
1034                         tab_cmd_dbdma(pb->last_cmd[fr],
1035                                         DBDMA_NOP | BR_ALWAYS,
1036                                         virt_to_bus(pb->ch1_cmd));
1037                         eieio();
1038                         pb->prev_last_fr = fr;
1039                         pb->last_fr = -2;
1040                 } else {
1041
1042                         IDEBUG("PlanB: active grabbing session detected\n");
1043
1044                         if(pb->need_pre_capture[fr]) {
1045
1046                                 IDEBUG("PlanB: padding pre-capture sequence\n");
1047
1048                                 tab_cmd_dbdma(pb->last_cmd[pb->last_fr],
1049                                                 DBDMA_NOP | BR_ALWAYS,
1050                                                 virt_to_bus(pb->pre_cmd[fr]));
1051                                 eieio();
1052                         } else {
1053                                 tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0);
1054                                 tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0);
1055                                 if(pb->gwidth[pb->last_fr] != pb->gwidth[fr]
1056                                         || pb->gheight[pb->last_fr] !=
1057                                                                 pb->gheight[fr]
1058                                         || pb->gfmt[pb->last_fr] !=
1059                                                                 pb->gfmt[fr])
1060                                         tab_cmd_dbdma((pb->cap_cmd[fr] + 1),
1061                                                                 DBDMA_NOP, 0);
1062                                 else
1063                                         tab_cmd_dbdma((pb->cap_cmd[fr] + 1),
1064                                             DBDMA_NOP | BR_ALWAYS,
1065                                             virt_to_bus(pb->cap_cmd[fr] + 16));
1066                                 tab_cmd_dbdma(pb->last_cmd[pb->last_fr],
1067                                                 DBDMA_NOP | BR_ALWAYS,
1068                                                 virt_to_bus(pb->cap_cmd[fr]));
1069                                 eieio();
1070                         }
1071                         pb->last_fr = fr;
1072                 }
1073                 if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) {
1074
1075                         IDEBUG("PlanB: became inactive in the mean time..."
1076                                 "reactivating\n");
1077
1078                         planb_dbdma_stop(&pb->planb_base->ch1);
1079                         out_le32 (&pb->planb_base->ch1.cmdptr,
1080                                                 virt_to_bus(pb->cap_cmd[fr]));
1081                         planb_dbdma_restart(&pb->planb_base->ch1);
1082                 }
1083         }
1084         pb->grabbing++;
1085         planb_unlock(pb);
1086
1087         return 0;
1088 }
1089
1090 static void planb_pre_capture(int fr, int bpp, struct planb *pb)
1091 {
1092         volatile struct dbdma_cmd *c1 = pb->pre_cmd[fr];
1093         int interlace = (pb->gheight[fr] > pb->maxlines/2)? 1: 0;
1094
1095         tab_cmd_dbdma(c1++, DBDMA_NOP, 0);
1096         if((c1 = cmd_geo_setup(c1, pb->gwidth[fr], pb->gheight[fr], interlace,
1097                                                 bpp, 0, pb)) == NULL) {
1098                 printk(KERN_WARNING "PlanB: encountered some problems\n");
1099                 tab_cmd_dbdma(pb->pre_cmd[fr] + 1, DBDMA_STOP, 0);
1100                 return;
1101         }
1102         /* Sync to even field */
1103         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel),
1104                 PLANB_SET(FIELD_SYNC));
1105         tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
1106         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
1107                 PLANB_SET(ODD_FIELD));
1108         tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
1109         tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++;
1110         tab_cmd_dbdma(c1++, DBDMA_NOP | INTR_ALWAYS, 0);
1111         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
1112                 PLANB_SET(DMA_ABORT));
1113         /* For non-interlaced, we use even fields only */
1114         if (pb->gheight[fr] <= pb->maxlines/2)
1115                 goto cmd_tab_data_end;
1116         /* Sync to odd field */
1117         tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
1118         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
1119                 PLANB_SET(ODD_FIELD));
1120         tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
1121         tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++;
1122         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
1123                 PLANB_SET(DMA_ABORT));
1124 cmd_tab_data_end:
1125         tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->cap_cmd[fr]));
1126
1127         eieio();
1128 }
1129
1130 static volatile struct dbdma_cmd *setup_grab_cmd(int fr, struct planb *pb)
1131 {
1132         int             i, bpp, count, nlines, stepsize, interlace;
1133 #ifdef PLANB_GSCANLINE
1134         int             scanline;
1135 #else
1136         int             nlpp, leftover1;
1137         unsigned long   base;
1138 #endif
1139         unsigned long   jump;
1140         int             pagei;
1141         volatile struct dbdma_cmd *c1;
1142         volatile struct dbdma_cmd *jump_addr;
1143
1144         c1 = pb->cap_cmd[fr];
1145         interlace = (pb->gheight[fr] > pb->maxlines/2)? 1: 0;
1146         bpp = pb->gfmt[fr];     /* gfmt = bpp */
1147         count = bpp * pb->gwidth[fr];
1148         nlines = pb->gheight[fr];
1149 #ifdef PLANB_GSCANLINE
1150         scanline = pb->gbytes_per_line;
1151 #else
1152         pb->lsize[fr] = count;
1153         pb->lnum[fr] = 0;
1154 #endif
1155
1156         /* Do video in: */
1157
1158         /* Preamble commands: */
1159         tab_cmd_dbdma(c1++, DBDMA_NOP, 0);
1160         tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(c1 + 16)); c1++;
1161         if((c1 = cmd_geo_setup(c1, pb->gwidth[fr], pb->gheight[fr], interlace,
1162                                                 bpp, 0, pb)) == NULL) {
1163                 printk(KERN_WARNING "PlanB: encountered serious problems\n");
1164                 tab_cmd_dbdma(pb->cap_cmd[fr] + 1, DBDMA_STOP, 0);
1165                 return (pb->cap_cmd[fr] + 2);
1166         }
1167         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel),
1168                 PLANB_SET(FIELD_SYNC));
1169         tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
1170         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
1171                 PLANB_SET(ODD_FIELD));
1172         tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
1173         tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++;
1174         tab_cmd_dbdma(c1++, DBDMA_NOP | INTR_ALWAYS, 0);
1175         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
1176                 PLANB_SET(DMA_ABORT));
1177
1178         if (interlace) {
1179                 stepsize = 2;
1180                 jump_addr = c1 + TAB_FACTOR * (nlines + 1) / 2;
1181         } else {
1182                 stepsize = 1;
1183                 jump_addr = c1 + TAB_FACTOR * nlines;
1184         }
1185         jump = virt_to_bus(jump_addr);
1186
1187         /* even field data: */
1188
1189         pagei = pb->gbuf_idx[fr];
1190 #ifdef PLANB_GSCANLINE
1191         for (i = 0; i < nlines; i += stepsize) {
1192                 tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count,
1193                                         virt_to_bus(pb->rawbuf[pagei
1194                                         + i * scanline / PAGE_SIZE]), jump);
1195         }
1196 #else
1197         i = 0;
1198         leftover1 = 0;
1199         do {
1200             int j;
1201
1202             base = virt_to_bus(pb->rawbuf[pagei]);
1203             nlpp = (PAGE_SIZE - leftover1) / count / stepsize;
1204             for(j = 0; j < nlpp && i < nlines; j++, i += stepsize, c1++)
1205                 tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET,
1206                           count, base + count * j * stepsize + leftover1, jump);
1207             if(i < nlines) {
1208                 int lov0 = PAGE_SIZE - count * nlpp * stepsize - leftover1;
1209
1210                 if(lov0 == 0)
1211                     leftover1 = 0;
1212                 else {
1213                     if(lov0 >= count) {
1214                         tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, base
1215                                 + count * nlpp * stepsize + leftover1, jump);
1216                     } else {
1217                         pb->l_to_addr[fr][pb->lnum[fr]] = pb->rawbuf[pagei]
1218                                         + count * nlpp * stepsize + leftover1;
1219                         pb->l_to_next_idx[fr][pb->lnum[fr]] = pagei + 1;
1220                         pb->l_to_next_size[fr][pb->lnum[fr]] = count - lov0;
1221                         tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count,
1222                                 virt_to_bus(pb->rawbuf[pb->l_fr_addr_idx[fr]
1223                                                 + pb->lnum[fr]]), jump);
1224                         if(++pb->lnum[fr] > MAX_LNUM)
1225                                 pb->lnum[fr]--;
1226                     }
1227                     leftover1 = count * stepsize - lov0;
1228                     i += stepsize;
1229                 }
1230             }
1231             pagei++;
1232         } while(i < nlines);
1233         tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, jump);
1234         c1 = jump_addr;
1235 #endif /* PLANB_GSCANLINE */
1236
1237         /* For non-interlaced, we use even fields only */
1238         if (!interlace)
1239                 goto cmd_tab_data_end;
1240
1241         /* Sync to odd field */
1242         tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
1243         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
1244                 PLANB_SET(ODD_FIELD));
1245         tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
1246         tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++;
1247         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
1248                 PLANB_SET(DMA_ABORT));
1249         
1250         /* odd field data: */
1251         jump_addr = c1 + TAB_FACTOR * nlines / 2;
1252         jump = virt_to_bus(jump_addr);
1253 #ifdef PLANB_GSCANLINE
1254         for (i = 1; i < nlines; i += stepsize) {
1255                 tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count,
1256                                         virt_to_bus(pb->rawbuf[pagei
1257                                         + i * scanline / PAGE_SIZE]), jump);
1258         }
1259 #else
1260         i = 1;
1261         leftover1 = 0;
1262         pagei = pb->gbuf_idx[fr];
1263         if(nlines <= 1)
1264             goto skip;
1265         do {
1266             int j;
1267
1268             base = virt_to_bus(pb->rawbuf[pagei]);
1269             nlpp = (PAGE_SIZE - leftover1) / count / stepsize;
1270             if(leftover1 >= count) {
1271                 tab_cmd_gen(c1++, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count,
1272                                                 base + leftover1 - count, jump);
1273                 i += stepsize;
1274             }
1275             for(j = 0; j < nlpp && i < nlines; j++, i += stepsize, c1++)
1276                 tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count,
1277                         base + count * (j * stepsize + 1) + leftover1, jump);
1278             if(i < nlines) {
1279                 int lov0 = PAGE_SIZE - count * nlpp * stepsize - leftover1;
1280
1281                 if(lov0 == 0)
1282                     leftover1 = 0;
1283                 else {
1284                     if(lov0 > count) {
1285                         pb->l_to_addr[fr][pb->lnum[fr]] = pb->rawbuf[pagei]
1286                                 + count * (nlpp * stepsize + 1) + leftover1;
1287                         pb->l_to_next_idx[fr][pb->lnum[fr]] = pagei + 1;
1288                         pb->l_to_next_size[fr][pb->lnum[fr]] = count * stepsize
1289                                                                         - lov0;
1290                         tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count,
1291                                 virt_to_bus(pb->rawbuf[pb->l_fr_addr_idx[fr]
1292                                                         + pb->lnum[fr]]), jump);
1293                         if(++pb->lnum[fr] > MAX_LNUM)
1294                                 pb->lnum[fr]--;
1295                         i += stepsize;
1296                     }
1297                     leftover1 = count * stepsize - lov0;
1298                 }
1299             }
1300             pagei++;
1301         } while(i < nlines);
1302 skip:
1303         tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, jump);
1304         c1 = jump_addr;
1305 #endif /* PLANB_GSCANLINE */
1306
1307 cmd_tab_data_end:
1308         tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->intr_stat),
1309                         (fr << 9) | PLANB_FRM_IRQ | PLANB_GEN_IRQ);
1310         /* stop it */
1311         tab_cmd_dbdma(c1, DBDMA_STOP, 0);
1312
1313         eieio();
1314         return c1;
1315 }
1316
1317 static void planb_irq(int irq, void *dev_id, struct pt_regs * regs)
1318 {
1319         unsigned int stat, astat;
1320         struct planb *pb = (struct planb *)dev_id;
1321
1322         IDEBUG("PlanB: planb_irq()\n");
1323
1324         /* get/clear interrupt status bits */
1325         eieio();
1326         stat = in_le32(&pb->planb_base->intr_stat);
1327         astat = stat & pb->intr_mask;
1328         out_le32(&pb->planb_base->intr_stat, PLANB_FRM_IRQ
1329                                         & ~astat & stat & ~PLANB_GEN_IRQ);
1330         IDEBUG("PlanB: stat = %X, astat = %X\n", stat, astat);
1331
1332         if(astat & PLANB_FRM_IRQ) {
1333                 unsigned int fr = stat >> 9;
1334 #ifndef PLANB_GSCANLINE
1335                 int i;
1336 #endif
1337                 IDEBUG("PlanB: PLANB_FRM_IRQ\n");
1338
1339                 pb->gcount++;
1340
1341                 IDEBUG("PlanB: grab %d: fr = %d, gcount = %d\n",
1342                                 pb->grabbing, fr, pb->gcount);
1343 #ifndef PLANB_GSCANLINE
1344                 IDEBUG("PlanB: %d * %d bytes are being copied over\n",
1345                                 pb->lnum[fr], pb->lsize[fr]);
1346                 for(i = 0; i < pb->lnum[fr]; i++) {
1347                         int first = pb->lsize[fr] - pb->l_to_next_size[fr][i];
1348
1349                         memcpy(pb->l_to_addr[fr][i],
1350                                 pb->rawbuf[pb->l_fr_addr_idx[fr] + i],
1351                                 first);
1352                         memcpy(pb->rawbuf[pb->l_to_next_idx[fr][i]],
1353                                 pb->rawbuf[pb->l_fr_addr_idx[fr] + i] + first,
1354                                                 pb->l_to_next_size[fr][i]);
1355                 }
1356 #endif
1357                 pb->frame_stat[fr] = GBUFFER_DONE;
1358                 pb->grabbing--;
1359                 wake_up_interruptible(&pb->capq);
1360                 return;
1361         }
1362         /* incorrect interrupts? */
1363         pb->intr_mask = PLANB_CLR_IRQ;
1364         out_le32(&pb->planb_base->intr_stat, PLANB_CLR_IRQ);
1365         printk(KERN_ERR "PlanB: IRQ lockup, cleared intrrupts"
1366                                                         " unconditionally\n");
1367 }
1368
1369 /*******************************
1370  * Device Operations functions *
1371  *******************************/
1372
1373 static int planb_open(struct video_device *dev, int mode)
1374 {
1375         struct planb *pb = (struct planb *)dev;
1376
1377         if (pb->user == 0) {
1378                 int err;
1379                 if((err = planb_prepare_open(pb)) != 0)
1380                         return err;
1381         }
1382         pb->user++;
1383
1384         DEBUG("PlanB: device opened\n");
1385         return 0;   
1386 }
1387
1388 static void planb_close(struct video_device *dev)
1389 {
1390         struct planb *pb = (struct planb *)dev;
1391
1392         if(pb->user < 1) /* ??? */
1393                 return;
1394         planb_lock(pb);
1395         if (pb->user == 1) {
1396                 if (pb->overlay) {
1397                         planb_dbdma_stop(&pb->planb_base->ch2);
1398                         planb_dbdma_stop(&pb->planb_base->ch1);
1399                         pb->overlay = 0;
1400                 }
1401                 planb_prepare_close(pb);
1402         }
1403         pb->user--;
1404         planb_unlock(pb);
1405
1406         DEBUG("PlanB: device closed\n");
1407 }
1408
1409 static long planb_read(struct video_device *v, char *buf, unsigned long count,
1410                                 int nonblock)
1411 {
1412         DEBUG("planb: read request\n");
1413         return -EINVAL;
1414 }
1415
1416 static long planb_write(struct video_device *v, const char *buf,
1417                                 unsigned long count, int nonblock)
1418 {
1419         DEBUG("planb: write request\n");
1420         return -EINVAL;
1421 }
1422
1423 static int planb_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
1424 {
1425         struct planb *pb=(struct planb *)dev;
1426         
1427         switch (cmd)
1428         {       
1429                 case VIDIOCGCAP:
1430                 {
1431                         struct video_capability b;
1432
1433                         DEBUG("PlanB: IOCTL VIDIOCGCAP\n");
1434
1435                         strcpy (b.name, pb->video_dev.name);
1436                         b.type = VID_TYPE_OVERLAY | VID_TYPE_CLIPPING |
1437                                  VID_TYPE_FRAMERAM | VID_TYPE_SCALES |
1438                                  VID_TYPE_CAPTURE;
1439                         b.channels = 2; /* composite & svhs */
1440                         b.audios = 0;
1441                         b.maxwidth = PLANB_MAXPIXELS;
1442                         b.maxheight = PLANB_MAXLINES;
1443                         b.minwidth = 32; /* wild guess */
1444                         b.minheight = 32;
1445                         if (copy_to_user(arg,&b,sizeof(b)))
1446                                 return -EFAULT;
1447                         return 0;
1448                 }
1449                 case VIDIOCSFBUF:
1450                 {
1451                         struct video_buffer v;
1452                         unsigned short bpp;
1453                         unsigned int fmt;
1454
1455                         DEBUG("PlanB: IOCTL VIDIOCSFBUF\n");
1456
1457                         if (!capable(CAP_SYS_ADMIN)
1458                         || !capable(CAP_SYS_RAWIO))
1459                                 return -EPERM;
1460                         if (copy_from_user(&v, arg,sizeof(v)))
1461                                 return -EFAULT;
1462                         planb_lock(pb);
1463                         switch(v.depth) {
1464                         case 8:
1465                                 bpp = 1;
1466                                 fmt = PLANB_GRAY;
1467                                 break;
1468                         case 15:
1469                         case 16:
1470                                 bpp = 2;
1471                                 fmt = PLANB_COLOUR15;
1472                                 break;
1473                         case 24:
1474                         case 32:
1475                                 bpp = 4;
1476                                 fmt = PLANB_COLOUR32;
1477                                 break;
1478                         default:
1479                                 planb_unlock(pb);
1480                                 return -EINVAL;
1481                         }
1482                         if (bpp * v.width > v.bytesperline) {
1483                                 planb_unlock(pb);
1484                                 return -EINVAL;
1485                         }
1486                         pb->win.bpp = bpp;
1487                         pb->win.color_fmt = fmt;
1488                         pb->frame_buffer_phys = (unsigned long) v.base;
1489                         pb->win.sheight = v.height;
1490                         pb->win.swidth = v.width;
1491                         pb->picture.depth = pb->win.depth = v.depth;
1492                         pb->win.bpl = pb->win.bpp * pb->win.swidth;
1493                         pb->win.pad = v.bytesperline - pb->win.bpl;
1494
1495                         DEBUG("PlanB: Display at %p is %d by %d, bytedepth %d,"
1496                                 " bpl %d (+ %d)\n", v.base, v.width,v.height,
1497                                 pb->win.bpp, pb->win.bpl, pb->win.pad);
1498
1499                         pb->cmd_buff_inited = 0;
1500                         if(pb->overlay) {
1501                                 suspend_overlay(pb);
1502                                 fill_cmd_buff(pb);
1503                                 resume_overlay(pb);
1504                         }
1505                         planb_unlock(pb);
1506                         return 0;               
1507                 }
1508                 case VIDIOCGFBUF:
1509                 {
1510                         struct video_buffer v;
1511
1512                         DEBUG("PlanB: IOCTL VIDIOCGFBUF\n");
1513
1514                         v.base = (void *)pb->frame_buffer_phys;
1515                         v.height = pb->win.sheight;
1516                         v.width = pb->win.swidth;
1517                         v.depth = pb->win.depth;
1518                         v.bytesperline = pb->win.bpl + pb->win.pad;
1519                         if (copy_to_user(arg, &v, sizeof(v)))
1520                                 return -EFAULT;
1521                         return 0;
1522                 }
1523                 case VIDIOCCAPTURE:
1524                 {
1525                         int i;
1526
1527                         if(copy_from_user(&i, arg, sizeof(i)))
1528                                 return -EFAULT;
1529                         if(i==0) {
1530                                 DEBUG("PlanB: IOCTL VIDIOCCAPTURE Stop\n");
1531
1532                                 if (!(pb->overlay))
1533                                         return 0;
1534                                 planb_lock(pb);
1535                                 pb->overlay = 0;
1536                                 overlay_stop(pb);
1537                                 planb_unlock(pb);
1538                         } else {
1539                                 DEBUG("PlanB: IOCTL VIDIOCCAPTURE Start\n");
1540
1541                                 if (pb->frame_buffer_phys == 0 ||
1542                                           pb->win.width == 0 ||
1543                                           pb->win.height == 0)
1544                                         return -EINVAL;
1545                                 if (pb->overlay)
1546                                         return 0;
1547                                 planb_lock(pb);
1548                                 pb->overlay = 1;
1549                                 if(!(pb->cmd_buff_inited))
1550                                         fill_cmd_buff(pb);
1551                                 overlay_start(pb);
1552                                 planb_unlock(pb);
1553                         }
1554                         return 0;
1555                 }
1556                 case VIDIOCGCHAN:
1557                 {
1558                         struct video_channel v;
1559
1560                         DEBUG("PlanB: IOCTL VIDIOCGCHAN\n");
1561
1562                         if(copy_from_user(&v, arg,sizeof(v)))
1563                                 return -EFAULT;
1564                         v.flags = 0;
1565                         v.tuners = 0;
1566                         v.type = VIDEO_TYPE_CAMERA;
1567                         v.norm = pb->win.norm;
1568                         switch(v.channel)
1569                         {
1570                         case 0:
1571                                 strcpy(v.name,"Composite");
1572                                 break;
1573                         case 1:
1574                                 strcpy(v.name,"SVHS");
1575                                 break;
1576                         default:
1577                                 return -EINVAL;
1578                                 break;
1579                         }
1580                         if(copy_to_user(arg,&v,sizeof(v)))
1581                                 return -EFAULT;
1582
1583                         return 0;
1584                 }
1585                 case VIDIOCSCHAN:
1586                 {
1587                         struct video_channel v;
1588
1589                         DEBUG("PlanB: IOCTL VIDIOCSCHAN\n");
1590
1591                         if(copy_from_user(&v, arg, sizeof(v)))
1592                                 return -EFAULT;
1593
1594                         if (v.norm != pb->win.norm) {
1595                                 int i, maxlines;
1596
1597                                 switch (v.norm)
1598                                 {
1599                                 case VIDEO_MODE_PAL:
1600                                 case VIDEO_MODE_SECAM:
1601                                         maxlines = PLANB_MAXLINES;
1602                                         break;
1603                                 case VIDEO_MODE_NTSC:
1604                                         maxlines = PLANB_NTSC_MAXLINES;
1605                                         break;
1606                                 default:
1607                                         return -EINVAL;
1608                                         break;
1609                                 }
1610                                 planb_lock(pb);
1611                                 /* empty the grabbing queue */
1612                                 while(pb->grabbing)
1613                                         interruptible_sleep_on(&pb->capq);
1614                                 pb->maxlines = maxlines;
1615                                 pb->win.norm = v.norm;
1616                                 /* Stop overlay if running */
1617                                 suspend_overlay(pb);
1618                                 for(i = 0; i < MAX_GBUFFERS; i++)
1619                                         pb->gnorm_switch[i] = 1;
1620                                 /* I know it's an overkill, but.... */
1621                                 fill_cmd_buff(pb);
1622                                 /* ok, now init it accordingly */
1623                                 saa_init_regs (pb);
1624                                 /* restart overlay if it was running */
1625                                 resume_overlay(pb);
1626                                 planb_unlock(pb);
1627                         }
1628
1629                         switch(v.channel)
1630                         {
1631                         case 0: /* Composite    */
1632                                 saa_set (SAA7196_IOCC,
1633                                         ((saa_regs[pb->win.norm][SAA7196_IOCC] &
1634                                           ~7) | 3), pb);
1635                                 break;
1636                         case 1: /* SVHS         */
1637                                 saa_set (SAA7196_IOCC,
1638                                         ((saa_regs[pb->win.norm][SAA7196_IOCC] &
1639                                           ~7) | 4), pb);
1640                                 break;
1641                         default:
1642                                 return -EINVAL;
1643                                 break;
1644                         }
1645
1646                         return 0;
1647                 }
1648                 case VIDIOCGPICT:
1649                 {
1650                         struct video_picture vp = pb->picture;
1651
1652                         DEBUG("PlanB: IOCTL VIDIOCGPICT\n");
1653
1654                         switch(pb->win.color_fmt) {
1655                         case PLANB_GRAY:
1656                                 vp.palette = VIDEO_PALETTE_GREY;
1657                         case PLANB_COLOUR15:
1658                                 vp.palette = VIDEO_PALETTE_RGB555;
1659                                 break;
1660                         case PLANB_COLOUR32:
1661                                 vp.palette = VIDEO_PALETTE_RGB32;
1662                                 break;
1663                         default:
1664                                 vp.palette = 0;
1665                                 break;
1666                         }
1667
1668                         if(copy_to_user(arg,&vp,sizeof(vp)))
1669                                 return -EFAULT;
1670                         return 0;
1671                 }
1672                 case VIDIOCSPICT:
1673                 {
1674                         struct video_picture vp;
1675
1676                         DEBUG("PlanB: IOCTL VIDIOCSPICT\n");
1677
1678                         if(copy_from_user(&vp,arg,sizeof(vp)))
1679                                 return -EFAULT;
1680                         pb->picture = vp;
1681                         /* Should we do sanity checks here? */
1682                         saa_set (SAA7196_BRIG, (unsigned char)
1683                             ((pb->picture.brightness) >> 8), pb);
1684                         saa_set (SAA7196_HUEC, (unsigned char)
1685                             ((pb->picture.hue) >> 8) ^ 0x80, pb);
1686                         saa_set (SAA7196_CSAT, (unsigned char)
1687                             ((pb->picture.colour) >> 9), pb);
1688                         saa_set (SAA7196_CONT, (unsigned char)
1689                             ((pb->picture.contrast) >> 9), pb);
1690
1691                         return 0;
1692                 }
1693                 case VIDIOCSWIN:
1694                 {
1695                         struct video_window     vw;
1696                         struct video_clip       clip;
1697                         int                     i;
1698                         
1699                         DEBUG("PlanB: IOCTL VIDIOCSWIN\n");
1700
1701                         if(copy_from_user(&vw,arg,sizeof(vw)))
1702                                 return -EFAULT;
1703
1704                         planb_lock(pb);
1705                         /* Stop overlay if running */
1706                         suspend_overlay(pb);
1707                         pb->win.interlace = (vw.height > pb->maxlines/2)? 1: 0;
1708                         if (pb->win.x != vw.x ||
1709                             pb->win.y != vw.y ||
1710                             pb->win.width != vw.width ||
1711                             pb->win.height != vw.height ||
1712                             !pb->cmd_buff_inited) {
1713                                 pb->win.x = vw.x;
1714                                 pb->win.y = vw.y;
1715                                 pb->win.width = vw.width;
1716                                 pb->win.height = vw.height;
1717                                 fill_cmd_buff(pb);
1718                         }
1719                         /* Reset clip mask */
1720                         memset ((void *) pb->mask, 0xff, (pb->maxlines
1721                                         * ((PLANB_MAXPIXELS + 7) & ~7)) / 8);
1722                         /* Add any clip rects */
1723                         for (i = 0; i < vw.clipcount; i++) {
1724                                 if (copy_from_user(&clip, vw.clips + i,
1725                                                 sizeof(struct video_clip)))
1726                                         return -EFAULT;
1727                                 add_clip(pb, &clip);
1728                         }
1729                         /* restart overlay if it was running */
1730                         resume_overlay(pb);
1731                         planb_unlock(pb);
1732                         return 0;
1733                 }
1734                 case VIDIOCGWIN:
1735                 {
1736                         struct video_window vw;
1737
1738                         DEBUG("PlanB: IOCTL VIDIOCGWIN\n");
1739
1740                         vw.x=pb->win.x;
1741                         vw.y=pb->win.y;
1742                         vw.width=pb->win.width;
1743                         vw.height=pb->win.height;
1744                         vw.chromakey=0;
1745                         vw.flags=0;
1746                         if(pb->win.interlace)
1747                                 vw.flags|=VIDEO_WINDOW_INTERLACE;
1748                         if(copy_to_user(arg,&vw,sizeof(vw)))
1749                                 return -EFAULT;
1750                         return 0;
1751                 }
1752                 case VIDIOCSYNC: {
1753                         int i;
1754
1755                         IDEBUG("PlanB: IOCTL VIDIOCSYNC\n");
1756
1757                         if(copy_from_user((void *)&i,arg,sizeof(int)))
1758                                 return -EFAULT;
1759
1760                         IDEBUG("PlanB: sync to frame %d\n", i);
1761
1762                         if(i > (MAX_GBUFFERS - 1) || i < 0)
1763                                 return -EINVAL;
1764 chk_grab:
1765                         switch (pb->frame_stat[i]) {
1766                         case GBUFFER_UNUSED:
1767                                 return -EINVAL;
1768                         case GBUFFER_GRABBING:
1769                                 IDEBUG("PlanB: waiting for grab"
1770                                                         " done (%d)\n", i);
1771                                 interruptible_sleep_on(&pb->capq);
1772                                 if(signal_pending(current))
1773                                         return -EINTR;
1774                                 goto chk_grab;
1775                         case GBUFFER_DONE:
1776                                 pb->frame_stat[i] = GBUFFER_UNUSED;
1777                                 break;
1778                         }
1779                         return 0;
1780                 }
1781
1782                 case VIDIOCMCAPTURE:
1783                 {
1784                         struct video_mmap vm;
1785                         volatile unsigned int status;
1786
1787                         IDEBUG("PlanB: IOCTL VIDIOCMCAPTURE\n");
1788
1789                         if(copy_from_user((void *) &vm,(void *)arg,sizeof(vm)))
1790                                 return -EFAULT;
1791                         status = pb->frame_stat[vm.frame];
1792                         if (status != GBUFFER_UNUSED)
1793                                 return -EBUSY;
1794
1795                         return vgrab(pb, &vm);
1796                 }
1797                 
1798                 case VIDIOCGMBUF:
1799                 {
1800                         int i;
1801                         struct video_mbuf vm;
1802
1803                         DEBUG("PlanB: IOCTL VIDIOCGMBUF\n");
1804
1805                         memset(&vm, 0 , sizeof(vm));
1806                         vm.size = PLANB_MAX_FBUF * MAX_GBUFFERS;
1807                         vm.frames = MAX_GBUFFERS;
1808                         for(i = 0; i<MAX_GBUFFERS; i++)
1809                                 vm.offsets[i] = PLANB_MAX_FBUF * i;
1810                         if(copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
1811                                 return -EFAULT;
1812                         return 0;
1813                 }
1814                 
1815                 case PLANBIOCGSAAREGS:
1816                 {
1817                         struct planb_saa_regs preg;
1818
1819                         DEBUG("PlanB: IOCTL PLANBIOCGSAAREGS\n");
1820
1821                         if(copy_from_user(&preg, arg, sizeof(preg)))
1822                                 return -EFAULT;
1823                         if(preg.addr >= SAA7196_NUMREGS)
1824                                 return -EINVAL;
1825                         preg.val = saa_regs[pb->win.norm][preg.addr];
1826                         if(copy_to_user((void *)arg, (void *)&preg,
1827                                                                 sizeof(preg)))
1828                                 return -EFAULT;
1829                         return 0;
1830                 }
1831                 
1832                 case PLANBIOCSSAAREGS:
1833                 {
1834                         struct planb_saa_regs preg;
1835
1836                         DEBUG("PlanB: IOCTL PLANBIOCSSAAREGS\n");
1837
1838                         if(copy_from_user(&preg, arg, sizeof(preg)))
1839                                 return -EFAULT;
1840                         if(preg.addr >= SAA7196_NUMREGS)
1841                                 return -EINVAL;
1842                         saa_set (preg.addr, preg.val, pb);
1843                         return 0;
1844                 }
1845                 
1846                 case PLANBIOCGSTAT:
1847                 {
1848                         struct planb_stat_regs pstat;
1849
1850                         DEBUG("PlanB: IOCTL PLANBIOCGSTAT\n");
1851
1852                         pstat.ch1_stat = in_le32(&pb->planb_base->ch1.status);
1853                         pstat.ch2_stat = in_le32(&pb->planb_base->ch2.status);
1854                         pstat.saa_stat0 = saa_status(0, pb);
1855                         pstat.saa_stat1 = saa_status(1, pb);
1856
1857                         if(copy_to_user((void *)arg, (void *)&pstat,
1858                                                         sizeof(pstat)))
1859                                 return -EFAULT;
1860                         return 0;
1861                 }
1862                 
1863                 case PLANBIOCSMODE: {
1864                         int v;
1865
1866                         DEBUG("PlanB: IOCTL PLANBIOCSMODE\n");
1867
1868                         if(copy_from_user(&v, arg, sizeof(v)))
1869                                 return -EFAULT;
1870
1871                         switch(v)
1872                         {
1873                         case PLANB_TV_MODE:
1874                                 saa_set (SAA7196_STDC,
1875                                         (saa_regs[pb->win.norm][SAA7196_STDC] &
1876                                           0x7f), pb);
1877                                 break;
1878                         case PLANB_VTR_MODE:
1879                                 saa_set (SAA7196_STDC,
1880                                         (saa_regs[pb->win.norm][SAA7196_STDC] |
1881                                           0x80), pb);
1882                                 break;
1883                         default:
1884                                 return -EINVAL;
1885                                 break;
1886                         }
1887                         pb->win.mode = v;
1888                         return 0;
1889                 }
1890                 case PLANBIOCGMODE: {
1891                         int v=pb->win.mode;
1892
1893                         DEBUG("PlanB: IOCTL PLANBIOCGMODE\n");
1894
1895                         if(copy_to_user(arg,&v,sizeof(v)))
1896                                 return -EFAULT;
1897                         return 0;
1898                 }
1899 #ifdef PLANB_GSCANLINE
1900                 case PLANBG_GRAB_BPL: {
1901                         int v=pb->gbytes_per_line;
1902
1903                         DEBUG("PlanB: IOCTL PLANBG_GRAB_BPL\n");
1904
1905                         if(copy_to_user(arg,&v,sizeof(v)))
1906                                 return -EFAULT;
1907                         return 0;
1908                 }
1909 #endif /* PLANB_GSCANLINE */
1910                 case PLANB_INTR_DEBUG: {
1911                         int i;
1912
1913                         DEBUG("PlanB: IOCTL PLANB_INTR_DEBUG\n");
1914
1915                         if(copy_from_user(&i, arg, sizeof(i)))
1916                                 return -EFAULT;
1917
1918                         /* avoid hang ups all together */
1919                         for (i = 0; i < MAX_GBUFFERS; i++) {
1920                                 if(pb->frame_stat[i] == GBUFFER_GRABBING) {
1921                                         pb->frame_stat[i] = GBUFFER_DONE;
1922                                 }
1923                         }
1924                         if(pb->grabbing)
1925                                 pb->grabbing--;
1926                         wake_up_interruptible(&pb->capq);
1927                         return 0;
1928                 }
1929                 case PLANB_INV_REGS: {
1930                         int i;
1931                         struct planb_any_regs any;
1932
1933                         DEBUG("PlanB: IOCTL PLANB_INV_REGS\n");
1934
1935                         if(copy_from_user(&any, arg, sizeof(any)))
1936                                 return -EFAULT;
1937                         if(any.offset < 0 || any.offset + any.bytes > 0x400)
1938                                 return -EINVAL;
1939                         if(any.bytes > 128)
1940                                 return -EINVAL;
1941                         for (i = 0; i < any.bytes; i++) {
1942                                 any.data[i] =
1943                                         in_8((unsigned char *)pb->planb_base
1944                                                         + any.offset + i);
1945                         }
1946                         if(copy_to_user(arg,&any,sizeof(any)))
1947                                 return -EFAULT;
1948                         return 0;
1949                 }
1950                 default:
1951                 {
1952                         DEBUG("PlanB: Unimplemented IOCTL\n");
1953                         return -ENOIOCTLCMD;
1954                 }
1955         /* Some IOCTLs are currently unsupported on PlanB */
1956                 case VIDIOCGTUNER: {
1957                 DEBUG("PlanB: IOCTL VIDIOCGTUNER\n");
1958                         goto unimplemented; }
1959                 case VIDIOCSTUNER: {
1960                 DEBUG("PlanB: IOCTL VIDIOCSTUNER\n");
1961                         goto unimplemented; }
1962                 case VIDIOCSFREQ: {
1963                 DEBUG("PlanB: IOCTL VIDIOCSFREQ\n");
1964                         goto unimplemented; }
1965                 case VIDIOCGFREQ: {
1966                 DEBUG("PlanB: IOCTL VIDIOCGFREQ\n");
1967                         goto unimplemented; }
1968                 case VIDIOCKEY: {
1969                 DEBUG("PlanB: IOCTL VIDIOCKEY\n");
1970                         goto unimplemented; }
1971                 case VIDIOCSAUDIO: {
1972                 DEBUG("PlanB: IOCTL VIDIOCSAUDIO\n");
1973                         goto unimplemented; }
1974                 case VIDIOCGAUDIO: {
1975                 DEBUG("PlanB: IOCTL VIDIOCGAUDIO\n");
1976                         goto unimplemented; }
1977 unimplemented:
1978                 DEBUG("       Unimplemented\n");
1979                         return -ENOIOCTLCMD;
1980         }
1981         return 0;
1982 }
1983
1984 static int planb_mmap(struct vm_area_struct *vma, struct video_device *dev, const char *adr, unsigned long size)
1985 {
1986         int i;
1987         struct planb *pb = (struct planb *)dev;
1988         unsigned long start = (unsigned long)adr;
1989
1990         if (size > MAX_GBUFFERS * PLANB_MAX_FBUF)
1991                 return -EINVAL;
1992         if (!pb->rawbuf) {
1993                 int err;
1994                 if((err=grabbuf_alloc(pb)))
1995                         return err;
1996         }
1997         for (i = 0; i < pb->rawbuf_size; i++) {
1998                 unsigned long pfn;
1999
2000                 pfn = virt_to_phys((void *)pb->rawbuf[i]) >> PAGE_SHIFT;
2001                 if (remap_pfn_range(vma, start, pfn, PAGE_SIZE, PAGE_SHARED))
2002                         return -EAGAIN;
2003                 start += PAGE_SIZE;
2004                 if (size <= PAGE_SIZE)
2005                         break;
2006                 size -= PAGE_SIZE;
2007         }
2008         return 0;
2009 }
2010
2011 static struct video_device planb_template=
2012 {
2013         .owner          = THIS_MODULE,
2014         .name           = PLANB_DEVICE_NAME,
2015         .type           = VID_TYPE_OVERLAY,
2016         .hardware       = VID_HARDWARE_PLANB,
2017         .open           = planb_open,
2018         .close          = planb_close,
2019         .read           = planb_read,
2020         .write          = planb_write,
2021         .ioctl          = planb_ioctl,
2022         .mmap           = planb_mmap,   /* mmap? */
2023 };
2024
2025 static int init_planb(struct planb *pb)
2026 {
2027         unsigned char saa_rev;
2028         int i, result;
2029
2030         memset ((void *) &pb->win, 0, sizeof (struct planb_window));
2031         /* Simple sanity check */
2032         if(def_norm >= NUM_SUPPORTED_NORM || def_norm < 0) {
2033                 printk(KERN_ERR "PlanB: Option(s) invalid\n");
2034                 return -2;
2035         }
2036         pb->win.norm = def_norm;
2037         pb->win.mode = PLANB_TV_MODE;   /* TV mode */
2038         pb->win.interlace=1;
2039         pb->win.x=0;
2040         pb->win.y=0;
2041         pb->win.width=768; /* 640 */
2042         pb->win.height=576; /* 480 */
2043         pb->maxlines=576;
2044 #if 0
2045         btv->win.cropwidth=768; /* 640 */
2046         btv->win.cropheight=576; /* 480 */
2047         btv->win.cropx=0;
2048         btv->win.cropy=0;
2049 #endif
2050         pb->win.pad=0;
2051         pb->win.bpp=4;
2052         pb->win.depth=32;
2053         pb->win.color_fmt=PLANB_COLOUR32;
2054         pb->win.bpl=1024*pb->win.bpp;
2055         pb->win.swidth=1024;
2056         pb->win.sheight=768;
2057 #ifdef PLANB_GSCANLINE
2058         if((pb->gbytes_per_line = PLANB_MAXPIXELS * 4) > PAGE_SIZE
2059                                 || (pb->gbytes_per_line <= 0))
2060                 return -3;
2061         else {
2062                 /* page align pb->gbytes_per_line for DMA purpose */
2063                 for(i = PAGE_SIZE; pb->gbytes_per_line < (i>>1);)
2064                         i>>=1;
2065                 pb->gbytes_per_line = i;
2066         }
2067 #endif
2068         pb->tab_size = PLANB_MAXLINES + 40;
2069         pb->suspend = 0;
2070         init_MUTEX(&pb->lock);
2071         pb->ch1_cmd = 0;
2072         pb->ch2_cmd = 0;
2073         pb->mask = 0;
2074         pb->priv_space = 0;
2075         pb->offset = 0;
2076         pb->user = 0;
2077         pb->overlay = 0;
2078         init_waitqueue_head(&pb->suspendq);
2079         pb->cmd_buff_inited = 0;
2080         pb->frame_buffer_phys = 0;
2081
2082         /* Reset DMA controllers */
2083         planb_dbdma_stop(&pb->planb_base->ch2);
2084         planb_dbdma_stop(&pb->planb_base->ch1);
2085
2086         saa_rev =  (saa_status(0, pb) & 0xf0) >> 4;
2087         printk(KERN_INFO "PlanB: SAA7196 video processor rev. %d\n", saa_rev);
2088         /* Initialize the SAA registers in memory and on chip */
2089         saa_init_regs (pb);
2090
2091         /* clear interrupt mask */
2092         pb->intr_mask = PLANB_CLR_IRQ;
2093
2094         result = request_irq(pb->irq, planb_irq, 0, "PlanB", (void *)pb);
2095         if (result < 0) {
2096                 if (result==-EINVAL)
2097                         printk(KERN_ERR "PlanB: Bad irq number (%d) "
2098                                                 "or handler\n", (int)pb->irq);
2099                 else if (result==-EBUSY)
2100                         printk(KERN_ERR "PlanB: I don't know why, "
2101                                         "but IRQ %d is busy\n", (int)pb->irq);
2102                 return result;
2103         }
2104         disable_irq(pb->irq);
2105         
2106         /* Now add the template and register the device unit. */
2107         memcpy(&pb->video_dev,&planb_template,sizeof(planb_template));
2108
2109         pb->picture.brightness=0x90<<8;
2110         pb->picture.contrast = 0x70 << 8;
2111         pb->picture.colour = 0x70<<8;
2112         pb->picture.hue = 0x8000;
2113         pb->picture.whiteness = 0;
2114         pb->picture.depth = pb->win.depth;
2115
2116         pb->frame_stat=NULL;
2117         init_waitqueue_head(&pb->capq);
2118         for(i=0; i<MAX_GBUFFERS; i++) {
2119                 pb->gbuf_idx[i] = PLANB_MAX_FBUF * i / PAGE_SIZE;
2120                 pb->gwidth[i]=0;
2121                 pb->gheight[i]=0;
2122                 pb->gfmt[i]=0;
2123                 pb->cap_cmd[i]=NULL;
2124 #ifndef PLANB_GSCANLINE
2125                 pb->l_fr_addr_idx[i] = MAX_GBUFFERS * (PLANB_MAX_FBUF
2126                                                 / PAGE_SIZE + 1) + MAX_LNUM * i;
2127                 pb->lsize[i] = 0;
2128                 pb->lnum[i] = 0;
2129 #endif
2130         }
2131         pb->rawbuf=NULL;
2132         pb->grabbing=0;
2133
2134         /* enable interrupts */
2135         out_le32(&pb->planb_base->intr_stat, PLANB_CLR_IRQ);
2136         pb->intr_mask = PLANB_FRM_IRQ;
2137         enable_irq(pb->irq);
2138
2139         if(video_register_device(&pb->video_dev, VFL_TYPE_GRABBER, video_nr)<0)
2140                 return -1;
2141
2142         return 0;
2143 }
2144
2145 /*
2146  *      Scan for a PlanB controller, request the irq and map the io memory 
2147  */
2148
2149 static int find_planb(void)
2150 {
2151         struct planb            *pb;
2152         struct device_node      *planb_devices;
2153         unsigned char           dev_fn, confreg, bus;
2154         unsigned int            old_base, new_base;
2155         unsigned int            irq;
2156         struct pci_dev          *pdev;
2157         int rc;
2158
2159         if (_machine != _MACH_Pmac)
2160                 return 0;
2161
2162         planb_devices = find_devices("planb");
2163         if (planb_devices == 0) {
2164                 planb_num=0;
2165                 printk(KERN_WARNING "PlanB: no device found!\n");
2166                 return planb_num;
2167         }
2168
2169         if (planb_devices->next != NULL)
2170                 printk(KERN_ERR "Warning: only using first PlanB device!\n");
2171         pb = &planbs[0];
2172         planb_num = 1;
2173
2174         if (planb_devices->n_addrs != 1) {
2175                 printk (KERN_WARNING "PlanB: expecting 1 address for planb "
2176                         "(got %d)", planb_devices->n_addrs);
2177                 return 0;
2178         }
2179
2180         if (planb_devices->n_intrs == 0) {
2181                 printk(KERN_WARNING "PlanB: no intrs for device %s\n",
2182                        planb_devices->full_name);
2183                 return 0;
2184         } else {
2185                 irq = planb_devices->intrs[0].line;
2186         }
2187
2188         /* Initialize PlanB's PCI registers */
2189
2190         /* There is a bug with the way OF assigns addresses
2191            to the devices behind the chaos bridge.
2192            control needs only 0x1000 of space, but decodes only
2193            the upper 16 bits. It therefore occupies a full 64K.
2194            OF assigns the planb controller memory within this space;
2195            so we need to change that here in order to access planb. */
2196
2197         /* We remap to 0xf1000000 in hope that nobody uses it ! */
2198
2199         bus = (planb_devices->addrs[0].space >> 16) & 0xff;
2200         dev_fn = (planb_devices->addrs[0].space >> 8) & 0xff;
2201         confreg = planb_devices->addrs[0].space & 0xff;
2202         old_base = planb_devices->addrs[0].address;
2203         new_base = 0xf1000000;
2204
2205         DEBUG("PlanB: Found on bus %d, dev %d, func %d, "
2206                 "membase 0x%x (base reg. 0x%x)\n",
2207                 bus, PCI_SLOT(dev_fn), PCI_FUNC(dev_fn), old_base, confreg);
2208
2209         pdev = pci_find_slot (bus, dev_fn);
2210         if (!pdev) {
2211                 printk(KERN_ERR "planb: cannot find slot\n");
2212                 goto err_out;
2213         }
2214
2215         /* Enable response in memory space, bus mastering,
2216            use memory write and invalidate */
2217         rc = pci_enable_device(pdev);
2218         if (rc) {
2219                 printk(KERN_ERR "planb: cannot enable PCI device %s\n",
2220                        pci_name(pdev));
2221                 goto err_out;
2222         }
2223         rc = pci_set_mwi(pdev);
2224         if (rc) {
2225                 printk(KERN_ERR "planb: cannot enable MWI on PCI device %s\n",
2226                        pci_name(pdev));
2227                 goto err_out_disable;
2228         }
2229         pci_set_master(pdev);
2230
2231         /* Set the new base address */
2232         pci_write_config_dword (pdev, confreg, new_base);
2233
2234         planb_regs = (volatile struct planb_registers *)
2235                                                 ioremap (new_base, 0x400);
2236         pb->planb_base = planb_regs;
2237         pb->planb_base_phys = (struct planb_registers *)new_base;
2238         pb->irq = irq;
2239         
2240         return planb_num;
2241
2242 err_out_disable:
2243         pci_disable_device(pdev);
2244 err_out:
2245         /* FIXME handle error */   /* comment moved from pci_find_slot, above */
2246         return 0;
2247 }
2248
2249 static void release_planb(void)
2250 {
2251         int i;
2252         struct planb *pb;
2253
2254         for (i=0;i<planb_num; i++) 
2255         {
2256                 pb=&planbs[i];
2257
2258                 /* stop and flash DMAs unconditionally */
2259                 planb_dbdma_stop(&pb->planb_base->ch2);
2260                 planb_dbdma_stop(&pb->planb_base->ch1);
2261
2262                 /* clear and free interrupts */
2263                 pb->intr_mask = PLANB_CLR_IRQ;
2264                 out_le32 (&pb->planb_base->intr_stat, PLANB_CLR_IRQ);
2265                 free_irq(pb->irq, pb);
2266
2267                 /* make sure all allocated memory are freed */
2268                 planb_prepare_close(pb);
2269
2270                 printk(KERN_INFO "PlanB: unregistering with v4l\n");
2271                 video_unregister_device(&pb->video_dev);
2272
2273                 /* note that iounmap() does nothing on the PPC right now */
2274                 iounmap ((void *)pb->planb_base);
2275         }
2276 }
2277
2278 static int __init init_planbs(void)
2279 {
2280         int i;
2281   
2282         if (find_planb()<=0)
2283                 return -EIO;
2284
2285         for (i=0; i<planb_num; i++) {
2286                 if (init_planb(&planbs[i])<0) {
2287                         printk(KERN_ERR "PlanB: error registering device %d"
2288                                                         " with v4l\n", i);
2289                         release_planb();
2290                         return -EIO;
2291                 } 
2292                 printk(KERN_INFO "PlanB: registered device %d with v4l\n", i);
2293         }  
2294         return 0;
2295 }
2296
2297 static void __exit exit_planbs(void)
2298 {
2299         release_planb();
2300 }
2301
2302 module_init(init_planbs);
2303 module_exit(exit_planbs);