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