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