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