~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/media/video/planb.c

Version: ~ [ 2.2.5 ] ~ [ 2.4.1 ] ~ [ 2.4.9 ] ~ [ 2.6.17.10 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.