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
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.