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