OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [media/] [video/] [planb.c] - Blame information for rev 62

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.