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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [media/] [video/] [saa5249.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *      Cleaned up to use existing videodev interface and allow the idea
3
 *      of multiple teletext decoders on the video4linux iface. Changed i2c
4
 *      to cover addressing clashes on device busses. It's also rebuilt so
5
 *      you can add arbitary multiple teletext devices to Linux video4linux
6
 *      now (well 32 anyway).
7
 *
8
 *      Alan Cox <Alan.Cox@linux.org>
9
 *
10
 *      The original driver was heavily modified to match the i2c interface
11
 *      It was truncated to use the WinTV boards, too.
12
 *
13
 *      Copyright (c) 1998 Richard Guenther <richard.guenther@student.uni-tuebingen.de>
14
 *
15
 * $Id: saa5249.c,v 1.1.1.1 2004-04-15 02:19:15 phoenix Exp $
16
 *
17
 *      Derived From
18
 *
19
 * vtx.c:
20
 * This is a loadable character-device-driver for videotext-interfaces
21
 * (aka teletext). Please check the Makefile/README for a list of supported
22
 * interfaces.
23
 *
24
 * Copyright (c) 1994-97 Martin Buck  <martin-2.buck@student.uni-ulm.de>
25
 *
26
 *
27
 * This program is free software; you can redistribute it and/or modify
28
 * it under the terms of the GNU General Public License as published by
29
 * the Free Software Foundation; either version 2 of the License, or
30
 * (at your option) any later version.
31
 *
32
 * This program is distributed in the hope that it will be useful,
33
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
34
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
35
 * GNU General Public License for more details.
36
 *
37
 * You should have received a copy of the GNU General Public License
38
 * along with this program; if not, write to the Free Software
39
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
40
 * USA.
41
 */
42
 
43
#include <linux/module.h>
44
#include <linux/kernel.h>
45
#include <linux/sched.h>
46
#include <linux/mm.h>
47
#include <linux/errno.h>
48
#include <linux/delay.h>
49
#include <linux/ioport.h>
50
#include <linux/slab.h>
51
#include <linux/init.h>
52
#include <stdarg.h>
53
#include <linux/i2c.h>
54
#include <linux/videotext.h>
55
#include <linux/videodev.h>
56
 
57
#include <asm/io.h>
58
#include <asm/uaccess.h>
59
 
60
#define VTX_VER_MAJ 1
61
#define VTX_VER_MIN 7
62
 
63
 
64
 
65
#define NUM_DAUS 4
66
#define NUM_BUFS 8
67
#define IF_NAME "SAA5249"
68
 
69
static const int disp_modes[8][3] =
70
{
71
        { 0x46, 0x03, 0x03 },   /* DISPOFF */
72
        { 0x46, 0xcc, 0xcc },   /* DISPNORM */
73
        { 0x44, 0x0f, 0x0f },   /* DISPTRANS */
74
        { 0x46, 0xcc, 0x46 },   /* DISPINS */
75
        { 0x44, 0x03, 0x03 },   /* DISPOFF, interlaced */
76
        { 0x44, 0xcc, 0xcc },   /* DISPNORM, interlaced */
77
        { 0x44, 0x0f, 0x0f },   /* DISPTRANS, interlaced */
78
        { 0x44, 0xcc, 0x46 }    /* DISPINS, interlaced */
79
};
80
 
81
 
82
 
83
#define PAGE_WAIT (300*HZ/1000)                 /* Time between requesting page and */
84
                                                /* checking status bits */
85
#define PGBUF_EXPIRE (15*HZ)                    /* Time to wait before retransmitting */
86
                                                /* page regardless of infobits */
87
typedef struct {
88
        u8 pgbuf[VTX_VIRTUALSIZE];              /* Page-buffer */
89
        u8 laststat[10];                        /* Last value of infobits for DAU */
90
        u8 sregs[7];                            /* Page-request registers */
91
        unsigned long expire;                   /* Time when page will be expired */
92
        unsigned clrfound : 1;                  /* VTXIOCCLRFOUND has been called */
93
        unsigned stopped : 1;                   /* VTXIOCSTOPDAU has been called */
94
} vdau_t;
95
 
96
struct saa5249_device
97
{
98
        vdau_t vdau[NUM_DAUS];                  /* Data for virtual DAUs (the 5249 only has one */
99
                                                /* real DAU, so we have to simulate some more) */
100
        int vtx_use_count;
101
        int is_searching[NUM_DAUS];
102
        int disp_mode;
103
        int virtual_mode;
104
        struct i2c_client *client;
105
        struct semaphore lock;
106
};
107
 
108
 
109
#define CCTWR 34                /* I²C write/read-address of vtx-chip */
110
#define CCTRD 35
111
#define NOACK_REPEAT 10         /* Retry access this many times on failure */
112
#define CLEAR_DELAY (HZ/20)     /* Time required to clear a page */
113
#define READY_TIMEOUT (30*HZ/1000)      /* Time to wait for ready signal of I²C-bus interface */
114
#define INIT_DELAY 500          /* Time in usec to wait at initialization of CEA interface */
115
#define START_DELAY 10          /* Time in usec to wait before starting write-cycle (CEA) */
116
 
117
#define VTX_DEV_MINOR 0
118
 
119
/* General defines and debugging support */
120
 
121
#ifndef FALSE
122
#define FALSE 0
123
#define TRUE 1
124
#endif
125
#ifndef MIN
126
#define MIN(a, b) ((a) < (b) ? (a) : (b))
127
#define MAX(a, b) ((a) > (b) ? (a) : (b))
128
#endif
129
 
130
#define RESCHED \
131
        do { \
132
          if (current->need_resched) \
133
            schedule(); \
134
        } while (0)
135
 
136
static struct video_device saa_template;        /* Declared near bottom */
137
 
138
/* Addresses to scan */
139
static unsigned short normal_i2c[] = {34>>1,I2C_CLIENT_END};
140
static unsigned short normal_i2c_range[] = {I2C_CLIENT_END};
141
static unsigned short probe[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
142
static unsigned short probe_range[2]  = { I2C_CLIENT_END, I2C_CLIENT_END };
143
static unsigned short ignore[2]       = { I2C_CLIENT_END, I2C_CLIENT_END };
144
static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
145
static unsigned short force[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
146
 
147
static struct i2c_client_address_data addr_data = {
148
        normal_i2c, normal_i2c_range,
149
        probe, probe_range,
150
        ignore, ignore_range,
151
        force
152
};
153
 
154
static struct i2c_client client_template;
155
 
156
static int saa5249_attach(struct i2c_adapter *adap, int addr, unsigned short flags, int kind)
157
{
158
        int pgbuf;
159
        int err;
160
        struct i2c_client *client;
161
        struct video_device *vd;
162
        struct saa5249_device *t;
163
 
164
        printk(KERN_INFO "saa5249: teletext chip found.\n");
165
        client=kmalloc(sizeof(*client), GFP_KERNEL);
166
        if(client==NULL)
167
                return -ENOMEM;
168
        client_template.adapter = adap;
169
        client_template.addr = addr;
170
        memcpy(client, &client_template, sizeof(*client));
171
        t = kmalloc(sizeof(*t), GFP_KERNEL);
172
        if(t==NULL)
173
        {
174
                kfree(client);
175
                return -ENOMEM;
176
        }
177
        memset(t, 0, sizeof(*t));
178
        strcpy(client->name, IF_NAME);
179
        init_MUTEX(&t->lock);
180
 
181
        /*
182
         *      Now create a video4linux device
183
         */
184
 
185
        client->data = vd=(struct video_device *)kmalloc(sizeof(struct video_device), GFP_KERNEL);
186
        if(vd==NULL)
187
        {
188
                kfree(t);
189
                kfree(client);
190
                return -ENOMEM;
191
        }
192
        memcpy(vd, &saa_template, sizeof(*vd));
193
 
194
        for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++)
195
        {
196
                memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
197
                memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs));
198
                memset(t->vdau[pgbuf].laststat, 0, sizeof(t->vdau[0].laststat));
199
                t->vdau[pgbuf].expire = 0;
200
                t->vdau[pgbuf].clrfound = TRUE;
201
                t->vdau[pgbuf].stopped = TRUE;
202
                t->is_searching[pgbuf] = FALSE;
203
        }
204
        vd->priv=t;
205
 
206
 
207
        /*
208
         *      Register it
209
         */
210
 
211
        if((err=video_register_device(vd, VFL_TYPE_VTX,-1))<0)
212
        {
213
                kfree(t);
214
                kfree(vd);
215
                kfree(client);
216
                return err;
217
        }
218
        t->client = client;
219
        i2c_attach_client(client);
220
        MOD_INC_USE_COUNT;
221
        return 0;
222
}
223
 
224
/*
225
 *      We do most of the hard work when we become a device on the i2c.
226
 */
227
 
228
static int saa5249_probe(struct i2c_adapter *adap)
229
{
230
        /* Only attach these chips to the BT848 bus for now */
231
 
232
        if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
233
        {
234
                return i2c_probe(adap, &addr_data, saa5249_attach);
235
        }
236
        return 0;
237
}
238
 
239
static int saa5249_detach(struct i2c_client *client)
240
{
241
        struct video_device *vd=client->data;
242
        i2c_detach_client(client);
243
        video_unregister_device(vd);
244
        kfree(vd->priv);
245
        kfree(vd);
246
        kfree(client);
247
        MOD_DEC_USE_COUNT;
248
        return 0;
249
}
250
 
251
static int saa5249_command(struct i2c_client *device,
252
                             unsigned int cmd, void *arg)
253
{
254
        return -EINVAL;
255
}
256
 
257
/* new I2C driver support */
258
 
259
static struct i2c_driver i2c_driver_videotext =
260
{
261
        IF_NAME,                /* name */
262
        I2C_DRIVERID_SAA5249, /* in i2c.h */
263
        I2C_DF_NOTIFY,
264
        saa5249_probe,
265
        saa5249_detach,
266
        saa5249_command
267
};
268
 
269
static struct i2c_client client_template = {
270
        "(unset)",
271
        -1,
272
        0,
273
        0,
274
        NULL,
275
        &i2c_driver_videotext
276
};
277
 
278
/*
279
 *      Wait the given number of jiffies (10ms). This calls the scheduler, so the actual
280
 *      delay may be longer.
281
 */
282
 
283
static void jdelay(unsigned long delay)
284
{
285
        sigset_t oldblocked = current->blocked;
286
 
287
        spin_lock_irq(&current->sigmask_lock);
288
        sigfillset(&current->blocked);
289
        recalc_sigpending(current);
290
        spin_unlock_irq(&current->sigmask_lock);
291
        current->state = TASK_INTERRUPTIBLE;
292
        schedule_timeout(delay);
293
 
294
        spin_lock_irq(&current->sigmask_lock);
295
        current->blocked = oldblocked;
296
        recalc_sigpending(current);
297
        spin_unlock_irq(&current->sigmask_lock);
298
}
299
 
300
 
301
/*
302
 *      I2C interfaces
303
 */
304
 
305
static int i2c_sendbuf(struct saa5249_device *t, int reg, int count, u8 *data)
306
{
307
        char buf[64];
308
 
309
        buf[0] = reg;
310
        memcpy(buf+1, data, count);
311
 
312
        if(i2c_master_send(t->client, buf, count+1)==count+1)
313
                return 0;
314
        return -1;
315
}
316
 
317
static int i2c_senddata(struct saa5249_device *t, ...)
318
{
319
        unsigned char buf[64];
320
        int v;
321
        int ct=0;
322
        va_list argp;
323
        va_start(argp,t);
324
 
325
        while((v=va_arg(argp,int))!=-1)
326
                buf[ct++]=v;
327
        return i2c_sendbuf(t, buf[0], ct-1, buf+1);
328
}
329
 
330
/* Get count number of bytes from I²C-device at address adr, store them in buf. Start & stop
331
 * handshaking is done by this routine, ack will be sent after the last byte to inhibit further
332
 * sending of data. If uaccess is TRUE, data is written to user-space with put_user.
333
 * Returns -1 if I²C-device didn't send acknowledge, 0 otherwise
334
 */
335
 
336
static int i2c_getdata(struct saa5249_device *t, int count, u8 *buf)
337
{
338
        if(i2c_master_recv(t->client, buf, count)!=count)
339
                return -1;
340
        return 0;
341
}
342
 
343
 
344
/*
345
 *      Standard character-device-driver functions
346
 */
347
 
348
static int do_saa5249_ioctl(struct saa5249_device *t, unsigned int cmd, void *arg)
349
{
350
        static int virtual_mode = FALSE;
351
 
352
        switch(cmd)
353
        {
354
                case VTXIOCGETINFO:
355
                {
356
                        vtx_info_t info;
357
                        info.version_major = VTX_VER_MAJ;
358
                        info.version_minor = VTX_VER_MIN;
359
                        info.numpages = NUM_DAUS;
360
                        /*info.cct_type = CCT_TYPE;*/
361
                        if(copy_to_user((void*)arg, &info, sizeof(vtx_info_t)))
362
                                return -EFAULT;
363
                        return 0;
364
                }
365
 
366
                case VTXIOCCLRPAGE:
367
                {
368
                        vtx_pagereq_t req;
369
 
370
                        if(copy_from_user(&req, (void*)arg, sizeof(vtx_pagereq_t)))
371
                                return -EFAULT;
372
                        if (req.pgbuf < 0 || req.pgbuf >= NUM_DAUS)
373
                                return -EINVAL;
374
                        memset(t->vdau[req.pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
375
                        t->vdau[req.pgbuf].clrfound = TRUE;
376
                        return 0;
377
                }
378
 
379
                case VTXIOCCLRFOUND:
380
                {
381
                        vtx_pagereq_t req;
382
 
383
                        if(copy_from_user(&req, (void*)arg, sizeof(vtx_pagereq_t)))
384
                                return -EFAULT;
385
                        if (req.pgbuf < 0 || req.pgbuf >= NUM_DAUS)
386
                                return -EINVAL;
387
                        t->vdau[req.pgbuf].clrfound = TRUE;
388
                        return 0;
389
                }
390
 
391
                case VTXIOCPAGEREQ:
392
                {
393
                        vtx_pagereq_t req;
394
                        if(copy_from_user(&req, (void*)arg, sizeof(vtx_pagereq_t)))
395
                                return -EFAULT;
396
                        if (!(req.pagemask & PGMASK_PAGE))
397
                                req.page = 0;
398
                        if (!(req.pagemask & PGMASK_HOUR))
399
                                req.hour = 0;
400
                        if (!(req.pagemask & PGMASK_MINUTE))
401
                                req.minute = 0;
402
                        if (req.page < 0 || req.page > 0x8ff) /* 7FF ?? */
403
                                return -EINVAL;
404
                        req.page &= 0x7ff;
405
                        if (req.hour < 0 || req.hour > 0x3f || req.minute < 0 || req.minute > 0x7f ||
406
                                req.pagemask < 0 || req.pagemask >= PGMASK_MAX || req.pgbuf < 0 || req.pgbuf >= NUM_DAUS)
407
                                return -EINVAL;
408
                        t->vdau[req.pgbuf].sregs[0] = (req.pagemask & PG_HUND ? 0x10 : 0) | (req.page / 0x100);
409
                        t->vdau[req.pgbuf].sregs[1] = (req.pagemask & PG_TEN ? 0x10 : 0) | ((req.page / 0x10) & 0xf);
410
                        t->vdau[req.pgbuf].sregs[2] = (req.pagemask & PG_UNIT ? 0x10 : 0) | (req.page & 0xf);
411
                        t->vdau[req.pgbuf].sregs[3] = (req.pagemask & HR_TEN ? 0x10 : 0) | (req.hour / 0x10);
412
                        t->vdau[req.pgbuf].sregs[4] = (req.pagemask & HR_UNIT ? 0x10 : 0) | (req.hour & 0xf);
413
                        t->vdau[req.pgbuf].sregs[5] = (req.pagemask & MIN_TEN ? 0x10 : 0) | (req.minute / 0x10);
414
                        t->vdau[req.pgbuf].sregs[6] = (req.pagemask & MIN_UNIT ? 0x10 : 0) | (req.minute & 0xf);
415
                        t->vdau[req.pgbuf].stopped = FALSE;
416
                        t->vdau[req.pgbuf].clrfound = TRUE;
417
                        t->is_searching[req.pgbuf] = TRUE;
418
                        return 0;
419
                }
420
 
421
                case VTXIOCGETSTAT:
422
                {
423
                        vtx_pagereq_t req;
424
                        u8 infobits[10];
425
                        vtx_pageinfo_t info;
426
                        int a;
427
 
428
                        if(copy_from_user(&req, (void*)arg, sizeof(vtx_pagereq_t)))
429
                                return -EFAULT;
430
                        if (req.pgbuf < 0 || req.pgbuf >= NUM_DAUS)
431
                                return -EINVAL;
432
                        if (!t->vdau[req.pgbuf].stopped)
433
                        {
434
                                if (i2c_senddata(t, 2, 0, -1) ||
435
                                        i2c_sendbuf(t, 3, sizeof(t->vdau[0].sregs), t->vdau[req.pgbuf].sregs) ||
436
                                        i2c_senddata(t, 8, 0, 25, 0, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', -1) ||
437
                                        i2c_senddata(t, 2, 0, t->vdau[req.pgbuf].sregs[0] | 8, -1) ||
438
                                        i2c_senddata(t, 8, 0, 25, 0, -1))
439
                                        return -EIO;
440
                                jdelay(PAGE_WAIT);
441
                                if (i2c_getdata(t, 10, infobits))
442
                                        return -EIO;
443
 
444
                                if (!(infobits[8] & 0x10) && !(infobits[7] & 0xf0) &&   /* check FOUND-bit */
445
                                        (memcmp(infobits, t->vdau[req.pgbuf].laststat, sizeof(infobits)) ||
446
                                        time_after_eq(jiffies, t->vdau[req.pgbuf].expire)))
447
                                {               /* check if new page arrived */
448
                                        if (i2c_senddata(t, 8, 0, 0, 0, -1) ||
449
                                                i2c_getdata(t, VTX_PAGESIZE, t->vdau[req.pgbuf].pgbuf))
450
                                                return -EIO;
451
                                        t->vdau[req.pgbuf].expire = jiffies + PGBUF_EXPIRE;
452
                                        memset(t->vdau[req.pgbuf].pgbuf + VTX_PAGESIZE, ' ', VTX_VIRTUALSIZE - VTX_PAGESIZE);
453
                                        if (t->virtual_mode)
454
                                        {
455
                                                /* Packet X/24 */
456
                                                if (i2c_senddata(t, 8, 0, 0x20, 0, -1) ||
457
                                                        i2c_getdata(t, 40, t->vdau[req.pgbuf].pgbuf + VTX_PAGESIZE + 20 * 40))
458
                                                        return -EIO;
459
                                                /* Packet X/27/0 */
460
                                                if (i2c_senddata(t, 8, 0, 0x21, 0, -1) ||
461
                                                        i2c_getdata(t, 40, t->vdau[req.pgbuf].pgbuf + VTX_PAGESIZE + 16 * 40))
462
                                                        return -EIO;
463
                                                /* Packet 8/30/0...8/30/15
464
                                                 * FIXME: AFAIK, the 5249 does hamming-decoding for some bytes in packet 8/30,
465
                                                 *        so we should undo this here.
466
                                                 */
467
                                                if (i2c_senddata(t, 8, 0, 0x22, 0, -1) ||
468
                                                        i2c_getdata(t, 40, t->vdau[req.pgbuf].pgbuf + VTX_PAGESIZE + 23 * 40))
469
                                                        return -EIO;
470
                                        }
471
                                        t->vdau[req.pgbuf].clrfound = FALSE;
472
                                        memcpy(t->vdau[req.pgbuf].laststat, infobits, sizeof(infobits));
473
                                }
474
                                else
475
                                {
476
                                        memcpy(infobits, t->vdau[req.pgbuf].laststat, sizeof(infobits));
477
                                }
478
                        }
479
                        else
480
                        {
481
                                memcpy(infobits, t->vdau[req.pgbuf].laststat, sizeof(infobits));
482
                        }
483
 
484
                        info.pagenum = ((infobits[8] << 8) & 0x700) | ((infobits[1] << 4) & 0xf0) | (infobits[0] & 0x0f);
485
                        if (info.pagenum < 0x100)
486
                                info.pagenum += 0x800;
487
                        info.hour = ((infobits[5] << 4) & 0x30) | (infobits[4] & 0x0f);
488
                        info.minute = ((infobits[3] << 4) & 0x70) | (infobits[2] & 0x0f);
489
                        info.charset = ((infobits[7] >> 1) & 7);
490
                        info.delete = !!(infobits[3] & 8);
491
                        info.headline = !!(infobits[5] & 4);
492
                        info.subtitle = !!(infobits[5] & 8);
493
                        info.supp_header = !!(infobits[6] & 1);
494
                        info.update = !!(infobits[6] & 2);
495
                        info.inter_seq = !!(infobits[6] & 4);
496
                        info.dis_disp = !!(infobits[6] & 8);
497
                        info.serial = !!(infobits[7] & 1);
498
                        info.notfound = !!(infobits[8] & 0x10);
499
                        info.pblf = !!(infobits[9] & 0x20);
500
                        info.hamming = 0;
501
                        for (a = 0; a <= 7; a++)
502
                        {
503
                                if (infobits[a] & 0xf0)
504
                                {
505
                                        info.hamming = 1;
506
                                        break;
507
                                }
508
                        }
509
                        if (t->vdau[req.pgbuf].clrfound)
510
                                info.notfound = 1;
511
                        if(copy_to_user(req.buffer, &info, sizeof(vtx_pageinfo_t)))
512
                                return -EFAULT;
513
                        if (!info.hamming && !info.notfound)
514
                        {
515
                                t->is_searching[req.pgbuf] = FALSE;
516
                        }
517
                        return 0;
518
                }
519
 
520
                case VTXIOCGETPAGE:
521
                {
522
                        vtx_pagereq_t req;
523
                        int start, end;
524
 
525
                        if(copy_from_user(&req, (void*)arg, sizeof(vtx_pagereq_t)))
526
                                return -EFAULT;
527
                        if (req.pgbuf < 0 || req.pgbuf >= NUM_DAUS || req.start < 0 ||
528
                                req.start > req.end || req.end >= (virtual_mode ? VTX_VIRTUALSIZE : VTX_PAGESIZE))
529
                                return -EINVAL;
530
                        if(copy_to_user(req.buffer, &t->vdau[req.pgbuf].pgbuf[req.start], req.end - req.start + 1))
531
                                return -EFAULT;
532
 
533
                         /*
534
                          *     Always read the time directly from SAA5249
535
                          */
536
 
537
                        if (req.start <= 39 && req.end >= 32)
538
                        {
539
                                int len;
540
                                char buf[16];
541
                                start = MAX(req.start, 32);
542
                                end = MIN(req.end, 39);
543
                                len=end-start+1;
544
                                if (i2c_senddata(t, 8, 0, 0, start, -1) ||
545
                                        i2c_getdata(t, len, buf))
546
                                        return -EIO;
547
                                if(copy_to_user(req.buffer+start-req.start, buf, len))
548
                                        return -EFAULT;
549
                        }
550
                        /* Insert the current header if DAU is still searching for a page */
551
                        if (req.start <= 31 && req.end >= 7 && t->is_searching[req.pgbuf])
552
                        {
553
                                char buf[32];
554
                                int len;
555
                                start = MAX(req.start, 7);
556
                                end = MIN(req.end, 31);
557
                                len=end-start+1;
558
                                if (i2c_senddata(t, 8, 0, 0, start, -1) ||
559
                                        i2c_getdata(t, len, buf))
560
                                        return -EIO;
561
                                if(copy_to_user(req.buffer+start-req.start, buf, len))
562
                                        return -EFAULT;
563
                        }
564
                        return 0;
565
                }
566
 
567
                case VTXIOCSTOPDAU:
568
                {
569
                        vtx_pagereq_t req;
570
 
571
                        if(copy_from_user(&req, (void*)arg, sizeof(vtx_pagereq_t)))
572
                                return -EFAULT;
573
                        if (req.pgbuf < 0 || req.pgbuf >= NUM_DAUS)
574
                                return -EINVAL;
575
                        t->vdau[req.pgbuf].stopped = TRUE;
576
                        t->is_searching[req.pgbuf] = FALSE;
577
                        return 0;
578
                }
579
 
580
                case VTXIOCPUTPAGE:
581
                case VTXIOCSETDISP:
582
                case VTXIOCPUTSTAT:
583
                        return 0;
584
 
585
                case VTXIOCCLRCACHE:
586
                {
587
                        if (i2c_senddata(t, 0, NUM_DAUS, 0, 8, -1) || i2c_senddata(t, 11,
588
                                ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
589
                                ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ', -1))
590
                                return -EIO;
591
                        if (i2c_senddata(t, 3, 0x20, -1))
592
                                return -EIO;
593
                        jdelay(10 * CLEAR_DELAY);                       /* I have no idea how long we have to wait here */
594
                        return 0;
595
                }
596
 
597
                case VTXIOCSETVIRT:
598
                {
599
                        /* The SAA5249 has virtual-row reception turned on always */
600
                        t->virtual_mode = (int)arg;
601
                        return 0;
602
                }
603
        }
604
        return -EINVAL;
605
}
606
 
607
/*
608
 *      Handle the locking
609
 */
610
 
611
static int saa5249_ioctl(struct video_device *vd, unsigned int cmd, void *arg)
612
{
613
        struct saa5249_device *t=vd->priv;
614
        int err;
615
 
616
        down(&t->lock);
617
        err = do_saa5249_ioctl(t, cmd, arg);
618
        up(&t->lock);
619
 
620
        return err;
621
}
622
 
623
static int saa5249_open(struct video_device *vd, int nb)
624
{
625
        struct saa5249_device *t=vd->priv;
626
        int pgbuf;
627
 
628
        if (t->client==NULL)
629
                return -ENODEV;
630
 
631
        if (i2c_senddata(t, 0, 0, -1) ||          /* Select R11 */
632
                                                /* Turn off parity checks (we do this ourselves) */
633
                i2c_senddata(t, 1, disp_modes[t->disp_mode][0], 0, -1) ||
634
                                                /* Display TV-picture, no virtual rows */
635
                i2c_senddata(t, 4, NUM_DAUS, disp_modes[t->disp_mode][1], disp_modes[t->disp_mode][2], 7, -1)) /* Set display to page 4 */
636
 
637
        {
638
                return -EIO;
639
        }
640
 
641
        for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++)
642
        {
643
                memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
644
                memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs));
645
                memset(t->vdau[pgbuf].laststat, 0, sizeof(t->vdau[0].laststat));
646
                t->vdau[pgbuf].expire = 0;
647
                t->vdau[pgbuf].clrfound = TRUE;
648
                t->vdau[pgbuf].stopped = TRUE;
649
                t->is_searching[pgbuf] = FALSE;
650
        }
651
        t->virtual_mode=FALSE;
652
        return 0;
653
}
654
 
655
 
656
 
657
static void saa5249_release(struct video_device *vd)
658
{
659
        struct saa5249_device *t=vd->priv;
660
        i2c_senddata(t, 1, 0x20, -1);           /* Turn off CCT */
661
        i2c_senddata(t, 5, 3, 3, -1);           /* Turn off TV-display */
662
        return;
663
}
664
 
665
static long saa5249_write(struct video_device *v, const char *buf, unsigned long l, int nb)
666
{
667
        return -EINVAL;
668
}
669
 
670
static int __init init_saa_5249 (void)
671
{
672
        printk(KERN_INFO "SAA5249 driver (" IF_NAME " interface) for VideoText version %d.%d\n",
673
                        VTX_VER_MAJ, VTX_VER_MIN);
674
        return i2c_add_driver(&i2c_driver_videotext);
675
}
676
 
677
static void __exit cleanup_saa_5249 (void)
678
{
679
        i2c_del_driver(&i2c_driver_videotext);
680
}
681
 
682
module_init(init_saa_5249);
683
module_exit(cleanup_saa_5249);
684
 
685
static struct video_device saa_template =
686
{
687
        owner:          THIS_MODULE,
688
        name:           IF_NAME,
689
        type:           VID_TYPE_TELETEXT,      /*| VID_TYPE_TUNER ?? */
690
        hardware:       VID_HARDWARE_SAA5249,
691
        open:           saa5249_open,
692
        close:          saa5249_release,
693
        write:          saa5249_write,
694
        ioctl:          saa5249_ioctl,
695
};
696
 
697
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

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